verifiers 0.2.2.dev54__tar.gz → 0.2.2.dev56__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.
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/PKG-INFO +1 -1
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/pyproject.toml +1 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/test_e2e.py +20 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/replay.py +2 -2
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/__init__.py +6 -0
- verifiers-0.2.2.dev56/verifiers/v1/harnesses/browser_use/__init__.py +6 -0
- verifiers-0.2.2.dev56/verifiers/v1/harnesses/browser_use/harness.py +125 -0
- verifiers-0.2.2.dev56/verifiers/v1/harnesses/browser_use/program.py +402 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/serve/server.py +2 -2
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/task.py +51 -75
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/taskset.py +0 -2
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/.gitignore +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/LICENSE +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/README.md +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/conftest.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_browser_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_build_script.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_cli_agent_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_client_auth_errors.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_client_config.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_client_multimodal_types.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_composable_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_context_token_metrics.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_decorator_ranks.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_endpoint_registry.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_env_group.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_env_server.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_environment.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_environment_extra.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_error_chain.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_eval_display.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_eval_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_gepa_cli.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_gepa_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_gym_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_harbor_env_mcp.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_imports.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_init_script.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_install_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_interception_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_logging.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_math_rubric.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_maybe_think_parser.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_message_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_message_utils_multimodal.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_multiturn_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_nemorl_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_openai_chat_completions_token_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_openai_responses_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_opencode_rlm_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_openenv_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_parser.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_path_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_per_turn_timing.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_pricing_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_prime_plugin.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_renderer_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_renderer_e2e.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_rlm_composable_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_rubric.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_rubric_group.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_sandbox_debug_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_sandbox_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_sandbox_mixin.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_save_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_setup_script.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_singleturn_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_stateful_tool_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_think_parser.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_tool_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_tool_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_trajectory_processing.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_tui_info_formatting.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_types.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/test_xml_parser.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/conftest.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/fixtures/counter_tool_v1.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/fixtures/duet_v1.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/fixtures/echo_acp_resume_v1.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/fixtures/echo_agentic_v1.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/fixtures/echo_multi_v0.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/fixtures/echo_tool_v1.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/fixtures/echo_user_sim_v1.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/fixtures/echo_v0.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/fixtures/echo_v1.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/fixtures/pyproject.toml +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/fixtures/tool_response_image_v1.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/test_color_codeword_tasks.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/test_configs.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/test_envs.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/test_graph.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/test_judges.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/test_legacy.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/test_scoring.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/test_taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/tests/v1/test_trace.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/cli/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/cli/commands/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/cli/commands/build.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/cli/commands/eval.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/cli/commands/gepa.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/cli/commands/init.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/cli/commands/install.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/cli/commands/setup.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/cli/plugins/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/cli/plugins/prime.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/cli/tui.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/clients/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/clients/anthropic_messages_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/clients/client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/clients/nemorl_chat_completions_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/clients/openai_chat_completions_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/clients/openai_chat_completions_token_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/clients/openai_completions_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/clients/openai_responses_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/clients/renderer_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/decorators.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/env_group.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/environment.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/README.md +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/cli_agent_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/README.md +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/_filter.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/composable_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/harnesses/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/harnesses/mini_swe_agent.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/harnesses/opencode.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/harnesses/prompt.txt +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/harnesses/rlm.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/sandbox_debug_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/swe_debug_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/task.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/cp/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/cp/cp_task.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/cp/test_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/harbor/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/harbor/cli_gym.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/harbor/harbor.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/harbor/terminal_lego.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/math/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/math/math_task.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/README.md +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/multi_swe/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/multi_swe/extract_fix_patch.sh +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/multi_swe/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/openswe/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/openswe/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/r2e_gym/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/r2e_gym/log_parser.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/r2e_gym/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/scale_swe/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/scale_swe/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/shared/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/shared/test_patch.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/swe_bench/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/swe_bench/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/swe_lego/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/swe_lego/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/swe_rebench_v2/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/swe_rebench_v2/log_parsers.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/swe_rebench_v2/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/swe_smith/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/swe_smith/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/composable/tasksets/swe/swe_tasksets.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/gym_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/harbor_env/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/harbor_env/env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/harbor_env/mcp.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/mcp_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/opencode_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/opencode_qa_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/opencode_rlm_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/sandbox_mixin.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/utils/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/utils/file_locks.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/experimental/utils/git_checkout_cache.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/README.md +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/browser_env/README.md +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/browser_env/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/browser_env/browser_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/browser_env/modes/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/browser_env/modes/base.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/browser_env/modes/cua_mode.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/browser_env/modes/dom_mode.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/openenv_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/reasoninggym_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/integrations/textarena_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/multiturn_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/python_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/sandbox_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/singleturn_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/stateful_tool_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/envs/tool_env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/errors.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/gepa/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/gepa/adapter.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/gepa/config.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/gepa/display.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/gepa/gepa_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/parsers/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/parsers/maybe_think_parser.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/parsers/parser.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/parsers/think_parser.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/parsers/xml_parser.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/rubrics/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/rubrics/experimental/hybrid_math_rubric.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/rubrics/judge_rubric.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/rubrics/math_rubric.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/rubrics/rubric.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/rubrics/rubric_group.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/scripts/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/scripts/build.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/scripts/eval.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/scripts/gepa.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/scripts/init.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/scripts/install.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/scripts/setup.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/scripts/tui.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/serve/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/serve/client/env_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/serve/client/zmq_env_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/serve/server/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/serve/server/env_router.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/serve/server/env_server.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/serve/server/env_worker.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/serve/server/zmq_env_server.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/serve/types.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/types.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/async_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/client_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/config_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/data_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/display_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/env_config_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/env_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/error_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/eval_display.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/eval_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/heartbeat.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/import_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/install_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/interception_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/logging_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/message_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/metric_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/path_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/pricing_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/process_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/response_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/save_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/serve_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/thread_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/threaded_sandbox_client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/tool_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/usage_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/utils/version_utils.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/acp/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/acp/_runner.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/agent.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/artifacts.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/dashboard/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/dashboard/base.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/dashboard/eval.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/dashboard/replay.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/dashboard/validate.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/debug.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/eval/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/eval/main.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/eval/resume.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/eval/runner.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/gepa.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/init.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/output.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/resolve.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/serve.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/cli/validate.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/clients/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/clients/client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/clients/config.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/clients/eval.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/clients/train.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/agent.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/cli/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/cli/debug.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/cli/env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/cli/eval.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/cli/init.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/cli/replay.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/cli/serve.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/cli/validate.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/judge.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/legacy.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/retries.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/serve.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/task.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/configs/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/decorators.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/dialects/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/dialects/anthropic.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/dialects/base.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/dialects/chat.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/dialects/responses.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/envs/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/envs/agentic_judge/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/envs/agentic_judge/env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/envs/best_of_n/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/envs/best_of_n/env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/envs/single_agent/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/envs/single_agent/env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/envs/user_sim/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/envs/user_sim/env.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/episode.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/errors.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/gepa/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/gepa/adapter.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/gepa/config.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/gepa/dataset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/gepa/reflection.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/gepa/runner.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/graph.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/bash/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/bash/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/bash/program.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/claude_code/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/claude_code/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/codex/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/codex/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/kimi_code/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/kimi_code/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/mini_swe_agent/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/mini_swe_agent/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/mini_swe_agent/program.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/null/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/null/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/null/program.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/pi/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/pi/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/pool/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/pool/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/rlm/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/rlm/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/terminus_2/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/terminus_2/harness.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/harnesses/terminus_2/program.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/interception/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/interception/base.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/interception/pool.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/interception/server.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/interception/tunnel/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/interception/tunnel/base.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/interception/tunnel/custom.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/interception/tunnel/prime.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/judge.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/judges/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/judges/reference.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/judges/reference.txt +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/judges/rubric.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/judges/rubric.txt +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/legacy.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/loaders.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/mcp/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/mcp/launch.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/mcp/server.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/mcp/toolset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/push.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/retries.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/rollout.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/runtimes/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/runtimes/base.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/runtimes/docker/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/runtimes/docker/egress.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/runtimes/limiters.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/runtimes/modal.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/runtimes/prime.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/runtimes/subprocess.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/scoring.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/serve/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/serve/client.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/serve/pool.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/serve/types.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/session.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/state.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/tasksets/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/tasksets/harbor/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/tasksets/harbor/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/tasksets/lean/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/tasksets/lean/scoring.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/tasksets/lean/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/tasksets/openenv/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/tasksets/openenv/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/tasksets/textarena/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/tasksets/textarena/taskset.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/trace.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/types.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/__init__.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/aio.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/compile.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/format.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/generic.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/git.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/image.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/install.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/interrupt.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/logging.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/memory.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/sampling.py +0 -0
- {verifiers-0.2.2.dev54 → verifiers-0.2.2.dev56}/verifiers/v1/utils/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: verifiers
|
|
3
|
-
Version: 0.2.2.
|
|
3
|
+
Version: 0.2.2.dev56
|
|
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
|
|
@@ -234,6 +234,7 @@ markers = [
|
|
|
234
234
|
"colocated: v1 e2e cases with a user/tool server colocated in the harness runtime",
|
|
235
235
|
"null: v1 e2e cases on the null harness",
|
|
236
236
|
"bash: v1 e2e cases on the bash harness",
|
|
237
|
+
"browser_use: v1 e2e cases on the browser_use harness",
|
|
237
238
|
"rlm: v1 e2e cases on the rlm harness",
|
|
238
239
|
"kimi_code: v1 e2e cases on the kimi-code harness",
|
|
239
240
|
"pi: v1 e2e cases on the pi harness",
|
|
@@ -118,6 +118,26 @@ async def test_single_turn(run_v1, harness, harness_runtime, tmp_path):
|
|
|
118
118
|
assert call.time.duration > 0
|
|
119
119
|
|
|
120
120
|
|
|
121
|
+
@pytest.mark.e2e
|
|
122
|
+
@pytest.mark.browser_use
|
|
123
|
+
@pytest.mark.docker
|
|
124
|
+
async def test_browser_use(run_v1, tmp_path):
|
|
125
|
+
"""The browser_use harness runs in an explicitly browser-capable runtime."""
|
|
126
|
+
image = (
|
|
127
|
+
"mcr.microsoft.com/playwright/python:v1.61.0-noble@"
|
|
128
|
+
"sha256:a9731514f24121d1dcd25d58d0a38146646d290a5998fd80d3e533e7b5e21c69"
|
|
129
|
+
)
|
|
130
|
+
(trace,) = await run_v1(
|
|
131
|
+
"echo-v1",
|
|
132
|
+
harness="browser_use",
|
|
133
|
+
runtime={"type": "docker", "image": image},
|
|
134
|
+
output_dir=tmp_path,
|
|
135
|
+
max_turns=2,
|
|
136
|
+
)
|
|
137
|
+
assert trace.ok
|
|
138
|
+
assert trace.reward == 1.0
|
|
139
|
+
|
|
140
|
+
|
|
121
141
|
@pytest.mark.e2e
|
|
122
142
|
@pytest.mark.parametrize("harness_runtime", USER_RUNTIMES, indirect=True)
|
|
123
143
|
async def test_user(run_v1, harness_runtime, tmp_path):
|
|
@@ -31,7 +31,7 @@ from verifiers.v1.cli.resolve import narrow_taskset_config
|
|
|
31
31
|
from verifiers.v1.configs.agent import WireAgentConfig
|
|
32
32
|
from verifiers.v1.configs.cli.replay import ReplayConfig
|
|
33
33
|
from verifiers.v1.state import state_cls
|
|
34
|
-
from verifiers.v1.task import Task, WireTaskData
|
|
34
|
+
from verifiers.v1.task import Task, WireTaskData
|
|
35
35
|
from verifiers.v1.trace import Trace
|
|
36
36
|
from verifiers.v1.utils.interrupt import install_interrupt
|
|
37
37
|
from verifiers.v1.utils.logging import setup_logging
|
|
@@ -76,7 +76,7 @@ async def run_replay(config: ReplayConfig, source: Path, out: Path) -> list[Trac
|
|
|
76
76
|
"score() — multi-agent runs don't support replay"
|
|
77
77
|
)
|
|
78
78
|
task_cls = vf.task_type(config.taskset.id)
|
|
79
|
-
data_cls =
|
|
79
|
+
data_cls = task_cls.data_type()
|
|
80
80
|
# `WireTaskData` reads any taskset's saved task without importing its Task type.
|
|
81
81
|
# An episode may hold no traces (its env hooks failed before any agent ran);
|
|
82
82
|
# there's nothing to re-score, so it drops out in the flatten. Each kept trace
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
from verifiers.v1.harnesses.bash import BashHarness, BashHarnessConfig
|
|
2
|
+
from verifiers.v1.harnesses.browser_use import (
|
|
3
|
+
BrowserUseHarness,
|
|
4
|
+
BrowserUseHarnessConfig,
|
|
5
|
+
)
|
|
2
6
|
from verifiers.v1.harnesses.claude_code import (
|
|
3
7
|
ClaudeCodeHarness,
|
|
4
8
|
ClaudeCodeHarnessConfig,
|
|
@@ -18,6 +22,8 @@ from verifiers.v1.harnesses.terminus_2 import Terminus2Harness, Terminus2Harness
|
|
|
18
22
|
__all__ = [
|
|
19
23
|
"BashHarness",
|
|
20
24
|
"BashHarnessConfig",
|
|
25
|
+
"BrowserUseHarness",
|
|
26
|
+
"BrowserUseHarnessConfig",
|
|
21
27
|
"ClaudeCodeHarness",
|
|
22
28
|
"ClaudeCodeHarnessConfig",
|
|
23
29
|
"CodexHarness",
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from pydantic import model_validator
|
|
6
|
+
|
|
7
|
+
from verifiers.v1.clients import ModelContext
|
|
8
|
+
from verifiers.v1.configs.harness import HarnessConfig
|
|
9
|
+
from verifiers.v1.dialects.chat import message_to_wire
|
|
10
|
+
from verifiers.v1.harness import Harness
|
|
11
|
+
from verifiers.v1.runtimes import ProgramResult, Runtime
|
|
12
|
+
from verifiers.v1.task import TaskData
|
|
13
|
+
from verifiers.v1.trace import Trace
|
|
14
|
+
|
|
15
|
+
PROGRAM_SOURCE = (Path(__file__).resolve().parent / "program.py").read_text()
|
|
16
|
+
|
|
17
|
+
# The helper names and persistence rules the model needs to use the local tool.
|
|
18
|
+
BROWSER_SYSTEM_PROMPT = """You are a browser automation agent. Your `browser` tool executes Python code that controls a real Chromium over CDP through browser-harness; its helpers are pre-imported.
|
|
19
|
+
|
|
20
|
+
Rules of the tool:
|
|
21
|
+
- Each call runs in a fresh Python process: variables do NOT persist between calls. The browser does persist — tabs, cookies, and page state carry over.
|
|
22
|
+
- Use print() for anything you want to see. Filter in Python before printing; a raw AX tree or DOM dump is huge.
|
|
23
|
+
- The first navigation is new_tab(url), not goto_url(url). After navigating, call wait_for_load().
|
|
24
|
+
|
|
25
|
+
Core helpers: new_tab(url), goto_url(url), page_info(), js(expression), click_at_xy(x, y), type_text(text), press_key(key), fill_input(selector, text), scroll(x, y, dy), wait_for_load(), wait_for_element(selector), wait_for_network_idle(), list_tabs(), switch_tab(target), close_tab(), ensure_real_tab(), capture_screenshot(path), upload_file(selector, path), and raw cdp("Domain.method", ...).
|
|
26
|
+
|
|
27
|
+
Finding elements: prefer the accessibility tree over screenshots. cdp("Accessibility.getFullAXTree")["nodes"] has every element's role, name, and backendDOMNodeId — filter in Python before printing. For coordinates: q = cdp("DOM.getBoxModel", backendNodeId=n)["model"]["content"]; x, y = sum(q[0::2])/4, sum(q[1::2])/4, then click_at_xy(x, y) and verify with a targeted js(...) or page_info() check. Fall back to js(...) over the DOM when the AX tree lacks the element."""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class BrowserUseHarnessConfig(HarnessConfig):
|
|
31
|
+
browser: Literal["chromium", "cdp"] = "chromium"
|
|
32
|
+
"""`chromium` launches locally; `cdp` attaches to `cdp_url` without owning it."""
|
|
33
|
+
|
|
34
|
+
cdp_url: str | None = None
|
|
35
|
+
"""Rollout-scoped HTTP or WebSocket endpoint used with `browser = "cdp"`."""
|
|
36
|
+
|
|
37
|
+
@model_validator(mode="after")
|
|
38
|
+
def _require_cdp_url_iff_cdp(self) -> "BrowserUseHarnessConfig":
|
|
39
|
+
if self.browser == "cdp" and not self.cdp_url:
|
|
40
|
+
raise ValueError(
|
|
41
|
+
"browser='cdp' needs cdp_url set to a CDP endpoint to attach to"
|
|
42
|
+
)
|
|
43
|
+
if self.browser != "cdp" and self.cdp_url:
|
|
44
|
+
raise ValueError(
|
|
45
|
+
f"cdp_url is only valid with browser='cdp', not browser={self.browser!r}"
|
|
46
|
+
)
|
|
47
|
+
return self
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class BrowserUseHarness(Harness[BrowserUseHarnessConfig]):
|
|
51
|
+
APPENDS_SYSTEM_PROMPT = True
|
|
52
|
+
SUPPORTS_MCP = True
|
|
53
|
+
SUPPORTS_RESUME = True
|
|
54
|
+
# The browser tool executes model-authored Python through a third-party daemon.
|
|
55
|
+
NEEDS_CONTAINER = True
|
|
56
|
+
|
|
57
|
+
async def setup(self, runtime: Runtime) -> None:
|
|
58
|
+
await runtime.prepare_uv_script(PROGRAM_SOURCE, self.config.resolved_env)
|
|
59
|
+
|
|
60
|
+
async def launch(
|
|
61
|
+
self,
|
|
62
|
+
ctx: ModelContext,
|
|
63
|
+
trace: Trace,
|
|
64
|
+
runtime: Runtime,
|
|
65
|
+
endpoint: str,
|
|
66
|
+
secret: str,
|
|
67
|
+
mcp_urls: dict[str, str],
|
|
68
|
+
data: TaskData,
|
|
69
|
+
) -> ProgramResult:
|
|
70
|
+
system_prompt, prompt = self.resolve_prompt(data)
|
|
71
|
+
system_prompt = "\n\n".join(
|
|
72
|
+
p for p in (BROWSER_SYSTEM_PROMPT, system_prompt) if p
|
|
73
|
+
)
|
|
74
|
+
# Default resume replays the transcript. If there was no task system
|
|
75
|
+
# prompt, that transcript already contains this harness prompt.
|
|
76
|
+
replaying_browser_prompt = (
|
|
77
|
+
data.system_prompt is None
|
|
78
|
+
and prompt is not None
|
|
79
|
+
and not isinstance(prompt, str)
|
|
80
|
+
and any(
|
|
81
|
+
message.role == "system" and message.content == BROWSER_SYSTEM_PROMPT
|
|
82
|
+
for message in prompt
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
env = {**self.config.resolved_env}
|
|
86
|
+
state = f".vf-browser-{trace.id}"
|
|
87
|
+
args = [
|
|
88
|
+
f"--base-url={endpoint}",
|
|
89
|
+
f"--api-key={secret}",
|
|
90
|
+
f"--model={ctx.model}",
|
|
91
|
+
f"--browser={self.config.browser}",
|
|
92
|
+
# A resumed segment reuses this trace's browser and profile.
|
|
93
|
+
f"--state-dir={state}",
|
|
94
|
+
]
|
|
95
|
+
if not replaying_browser_prompt:
|
|
96
|
+
args.append(f"--system-prompt={system_prompt}")
|
|
97
|
+
if self.config.cdp_url:
|
|
98
|
+
args.append(f"--cdp-url={self.config.cdp_url}")
|
|
99
|
+
if mcp_urls:
|
|
100
|
+
# The program connects to the tool servers over HTTP; hand it a standard
|
|
101
|
+
# `mcpServers` URL config (the `mcp` client itself comes from the uv deps).
|
|
102
|
+
args.append(
|
|
103
|
+
"--mcp-config="
|
|
104
|
+
+ json.dumps(
|
|
105
|
+
{
|
|
106
|
+
"mcpServers": {
|
|
107
|
+
name: {"url": url} for name, url in mcp_urls.items()
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
)
|
|
112
|
+
if isinstance(prompt, str):
|
|
113
|
+
args.append(f"--prompt={prompt}")
|
|
114
|
+
elif prompt is not None:
|
|
115
|
+
# Base64 images can exceed exec limits, so hand Messages off through a file.
|
|
116
|
+
path = f".vf-initial-messages-{trace.id}.json"
|
|
117
|
+
await runtime.write(
|
|
118
|
+
path,
|
|
119
|
+
json.dumps([message_to_wire(m) for m in prompt]).encode(),
|
|
120
|
+
)
|
|
121
|
+
args.append(f"--initial-messages-file={path}")
|
|
122
|
+
program = await runtime.prepare_uv_script(
|
|
123
|
+
PROGRAM_SOURCE, self.config.resolved_env
|
|
124
|
+
)
|
|
125
|
+
return await runtime.run_program([*program, *args], env)
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
# /// script
|
|
2
|
+
# requires-python = ">=3.10"
|
|
3
|
+
# dependencies = [
|
|
4
|
+
# "browser-harness==0.1.8",
|
|
5
|
+
# "openai",
|
|
6
|
+
# "mcp>=1.24.0,<2",
|
|
7
|
+
# "httpx",
|
|
8
|
+
# "tenacity",
|
|
9
|
+
# ]
|
|
10
|
+
# ///
|
|
11
|
+
"""A chat loop whose one local tool drives a real Chromium over CDP.
|
|
12
|
+
|
|
13
|
+
Each tool call pipes the model's code to browser-harness, whose daemon holds the
|
|
14
|
+
CDP connection and pre-imports its page helpers. `chromium` launches and owns a
|
|
15
|
+
local browser; `cdp` attaches to an HTTP or WebSocket endpoint it does not own.
|
|
16
|
+
Trace-scoped state preserves tabs across resume and records owned process IDs.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
import asyncio
|
|
21
|
+
import json
|
|
22
|
+
import os
|
|
23
|
+
import re
|
|
24
|
+
import shutil
|
|
25
|
+
import subprocess
|
|
26
|
+
import sys
|
|
27
|
+
import time
|
|
28
|
+
import urllib.request
|
|
29
|
+
from contextlib import AsyncExitStack, asynccontextmanager, suppress
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
from typing import Any, cast
|
|
32
|
+
from urllib.parse import urlsplit
|
|
33
|
+
|
|
34
|
+
import httpx
|
|
35
|
+
from openai import AsyncOpenAI
|
|
36
|
+
from tenacity import AsyncRetrying, stop_after_attempt, wait_exponential_jitter
|
|
37
|
+
|
|
38
|
+
MCP_CALL_ATTEMPTS = 6
|
|
39
|
+
MCP_TIMEOUT = httpx.Timeout(600.0, connect=5.0) # the OpenAI SDK client defaults
|
|
40
|
+
|
|
41
|
+
BROWSER_TOOL_TIMEOUT = 3600
|
|
42
|
+
"""Matches the bash harness's command timeout."""
|
|
43
|
+
|
|
44
|
+
BROWSER_READY_TIMEOUT = 60
|
|
45
|
+
"""The documented Playwright image announced CDP in under one second from a
|
|
46
|
+
cold container; one minute leaves ample runtime startup headroom."""
|
|
47
|
+
|
|
48
|
+
_DEVTOOLS_LINE = re.compile(r"DevTools listening on ws://127\.0\.0\.1:(\d+)/")
|
|
49
|
+
|
|
50
|
+
BROWSER_TOOL = {
|
|
51
|
+
"type": "function",
|
|
52
|
+
"function": {
|
|
53
|
+
"name": "browser",
|
|
54
|
+
"description": (
|
|
55
|
+
"Execute Python code that drives the browser through browser-harness. "
|
|
56
|
+
"Helpers are pre-imported; use print() to see values. Each call runs in "
|
|
57
|
+
"a fresh process: Python variables do not persist between calls, but the "
|
|
58
|
+
"browser (tabs, cookies, page state) does."
|
|
59
|
+
),
|
|
60
|
+
"parameters": {
|
|
61
|
+
"type": "object",
|
|
62
|
+
"properties": {
|
|
63
|
+
"code": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"description": "The Python code to execute.",
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"required": ["code"],
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def find_browser() -> str:
|
|
75
|
+
"""The Chromium binary to launch, where a machine keeps one.
|
|
76
|
+
|
|
77
|
+
`PLAYWRIGHT_BROWSERS_PATH` before PATH: an image that installs browsers
|
|
78
|
+
through Playwright puts nothing on PATH.
|
|
79
|
+
"""
|
|
80
|
+
for key in ("BH_CHROME_PATH", "CHROME_PATH"):
|
|
81
|
+
candidate = os.environ.get(key)
|
|
82
|
+
if candidate and os.access(candidate, os.X_OK):
|
|
83
|
+
return candidate
|
|
84
|
+
registry = os.environ.get("PLAYWRIGHT_BROWSERS_PATH")
|
|
85
|
+
if registry:
|
|
86
|
+
builds = sorted(Path(registry).glob("chromium-*/chrome-linux*/chrome"))
|
|
87
|
+
if builds:
|
|
88
|
+
return str(builds[-1])
|
|
89
|
+
for name in (
|
|
90
|
+
"google-chrome-stable",
|
|
91
|
+
"google-chrome",
|
|
92
|
+
"chromium",
|
|
93
|
+
"chromium-browser",
|
|
94
|
+
):
|
|
95
|
+
found = shutil.which(name)
|
|
96
|
+
if found:
|
|
97
|
+
return found
|
|
98
|
+
raise SystemExit(
|
|
99
|
+
"no Chromium/Chrome found; run on a browser-capable image "
|
|
100
|
+
"(e.g. mcr.microsoft.com/playwright/python) or set BH_CHROME_PATH"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _endpoint_alive(endpoint: str) -> bool:
|
|
105
|
+
try:
|
|
106
|
+
# browser-harness uses five seconds for this same DevTools HTTP probe.
|
|
107
|
+
urllib.request.urlopen(f"{endpoint}/json/version", timeout=5).close()
|
|
108
|
+
return True
|
|
109
|
+
except OSError:
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def ensure_chromium(state_dir: Path) -> str:
|
|
114
|
+
"""Reuse this trace's live Chromium or launch it."""
|
|
115
|
+
endpoint_file = state_dir / "cdp-endpoint"
|
|
116
|
+
if endpoint_file.exists():
|
|
117
|
+
endpoint = endpoint_file.read_text().strip()
|
|
118
|
+
if endpoint and _endpoint_alive(endpoint):
|
|
119
|
+
return endpoint
|
|
120
|
+
|
|
121
|
+
profile = state_dir / "profile"
|
|
122
|
+
profile.mkdir(parents=True, exist_ok=True)
|
|
123
|
+
log = state_dir / "browser.log"
|
|
124
|
+
with open(log, "wb") as stderr:
|
|
125
|
+
browser = subprocess.Popen(
|
|
126
|
+
[
|
|
127
|
+
find_browser(),
|
|
128
|
+
"--remote-debugging-port=0",
|
|
129
|
+
f"--user-data-dir={profile}",
|
|
130
|
+
"--headless",
|
|
131
|
+
"--no-first-run",
|
|
132
|
+
"--no-default-browser-check",
|
|
133
|
+
"--disable-dev-shm-usage",
|
|
134
|
+
"--no-sandbox",
|
|
135
|
+
],
|
|
136
|
+
stdout=subprocess.DEVNULL,
|
|
137
|
+
stderr=stderr,
|
|
138
|
+
stdin=subprocess.DEVNULL,
|
|
139
|
+
start_new_session=True,
|
|
140
|
+
)
|
|
141
|
+
deadline = time.monotonic() + BROWSER_READY_TIMEOUT
|
|
142
|
+
while time.monotonic() < deadline and browser.poll() is None:
|
|
143
|
+
output = log.read_text(errors="replace")
|
|
144
|
+
if match := _DEVTOOLS_LINE.search(output):
|
|
145
|
+
endpoint = f"http://127.0.0.1:{match.group(1)}"
|
|
146
|
+
endpoint_file.write_text(endpoint)
|
|
147
|
+
return endpoint
|
|
148
|
+
time.sleep(0.1)
|
|
149
|
+
if browser.poll() is None:
|
|
150
|
+
browser.kill()
|
|
151
|
+
browser.wait()
|
|
152
|
+
tail = log.read_text(errors="replace")[-2000:]
|
|
153
|
+
raise SystemExit(
|
|
154
|
+
f"browser did not announce a DevTools port within {BROWSER_READY_TIMEOUT}s: "
|
|
155
|
+
f"{tail or '<no browser output>'}"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def run_browser(code: str, env: dict[str, str]) -> str:
|
|
160
|
+
"""Run model code through the pinned browser-harness CLI."""
|
|
161
|
+
try:
|
|
162
|
+
result = subprocess.run(
|
|
163
|
+
[sys.executable, "-m", "browser_harness.run"],
|
|
164
|
+
input=code,
|
|
165
|
+
capture_output=True,
|
|
166
|
+
text=True,
|
|
167
|
+
timeout=BROWSER_TOOL_TIMEOUT,
|
|
168
|
+
env=env,
|
|
169
|
+
check=False,
|
|
170
|
+
)
|
|
171
|
+
return (result.stdout + result.stderr) or "(no output)"
|
|
172
|
+
except Exception as e: # noqa: BLE001 - tool failures are returned to the model
|
|
173
|
+
return f"error: {e}"
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
async def chat(
|
|
177
|
+
client: AsyncOpenAI,
|
|
178
|
+
model: str,
|
|
179
|
+
messages: list[dict[str, Any]],
|
|
180
|
+
tools: list[dict[str, Any]],
|
|
181
|
+
):
|
|
182
|
+
completion = await client.chat.completions.create(
|
|
183
|
+
model=model,
|
|
184
|
+
messages=cast(Any, messages),
|
|
185
|
+
tools=cast(Any, tools or None),
|
|
186
|
+
)
|
|
187
|
+
return completion.choices[0].message
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@asynccontextmanager
|
|
191
|
+
async def mcp_session(spec: dict):
|
|
192
|
+
"""One fresh streamable-HTTP session to an MCP server, opened and closed within the caller's
|
|
193
|
+
task so AnyIO cancellation scopes stay correctly nested. A teardown failure after the body
|
|
194
|
+
completed is swallowed — the result is already in hand, and closing noise must not fail (or
|
|
195
|
+
replay) an already-answered call."""
|
|
196
|
+
from mcp import ClientSession
|
|
197
|
+
from mcp.client.streamable_http import (
|
|
198
|
+
create_mcp_http_client,
|
|
199
|
+
streamable_http_client,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
stack = AsyncExitStack()
|
|
203
|
+
try:
|
|
204
|
+
http_client = await stack.enter_async_context(
|
|
205
|
+
create_mcp_http_client(
|
|
206
|
+
headers=spec.get("headers") or None, timeout=MCP_TIMEOUT
|
|
207
|
+
)
|
|
208
|
+
)
|
|
209
|
+
read, write, *_ = await stack.enter_async_context(
|
|
210
|
+
streamable_http_client(spec["url"], http_client=http_client)
|
|
211
|
+
)
|
|
212
|
+
session = await stack.enter_async_context(ClientSession(read, write))
|
|
213
|
+
await session.initialize()
|
|
214
|
+
yield session
|
|
215
|
+
finally:
|
|
216
|
+
with suppress(Exception):
|
|
217
|
+
await stack.aclose()
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
async def with_retry(call):
|
|
221
|
+
"""Run one session-scoped operation, retrying transient failures with backoff. A call whose
|
|
222
|
+
response was lost may be replayed — MCP has no idempotency key, so tools should tolerate
|
|
223
|
+
at-least-once delivery (a tool that fails reports through its result, not an exception)."""
|
|
224
|
+
async for attempt in AsyncRetrying(
|
|
225
|
+
stop=stop_after_attempt(MCP_CALL_ATTEMPTS),
|
|
226
|
+
wait=wait_exponential_jitter(initial=0.5, max=30),
|
|
227
|
+
reraise=True,
|
|
228
|
+
):
|
|
229
|
+
with attempt:
|
|
230
|
+
return await call()
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
async def connect_mcp(
|
|
234
|
+
config: dict, reserved: set[str]
|
|
235
|
+
) -> tuple[list[dict], dict, dict]:
|
|
236
|
+
"""Enumerate each configured MCP server's tools (a streamable-HTTP `url`); return (tool schemas,
|
|
237
|
+
dispatch mapping `<server>_<tool>` -> (server name, raw tool name), servers mapping name -> spec).
|
|
238
|
+
No session is held — a stateless-HTTP server is reconnected per call."""
|
|
239
|
+
tool_schemas: list[dict] = []
|
|
240
|
+
dispatch: dict[str, tuple] = {}
|
|
241
|
+
servers: dict[str, dict] = {}
|
|
242
|
+
for name, spec in config.get("mcpServers", {}).items():
|
|
243
|
+
servers[name] = spec
|
|
244
|
+
|
|
245
|
+
async def list_tools(spec: dict = spec):
|
|
246
|
+
async with mcp_session(spec) as session:
|
|
247
|
+
return (await session.list_tools()).tools
|
|
248
|
+
|
|
249
|
+
for tool in await with_retry(list_tools):
|
|
250
|
+
# A server named "" (TOOL_PREFIX = None) advertises its tools bare.
|
|
251
|
+
full = f"{name}_{tool.name}" if name else tool.name
|
|
252
|
+
if full in reserved or full in dispatch:
|
|
253
|
+
raise ValueError(
|
|
254
|
+
f"duplicate tool name {full!r}; keep MCP tool names qualified"
|
|
255
|
+
)
|
|
256
|
+
tool_schemas.append(
|
|
257
|
+
{
|
|
258
|
+
"type": "function",
|
|
259
|
+
"function": {
|
|
260
|
+
"name": full,
|
|
261
|
+
"description": tool.description or "",
|
|
262
|
+
"parameters": tool.inputSchema,
|
|
263
|
+
},
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
dispatch[full] = (name, tool.name)
|
|
267
|
+
return tool_schemas, dispatch, servers
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def mcp_content_to_chat_content(blocks) -> str | list[dict]:
|
|
271
|
+
parts = []
|
|
272
|
+
for block in blocks:
|
|
273
|
+
if block.type == "text":
|
|
274
|
+
parts.append({"type": "text", "text": block.text})
|
|
275
|
+
elif block.type == "image":
|
|
276
|
+
url = f"data:{block.mimeType};base64,{block.data}"
|
|
277
|
+
parts.append({"type": "image_url", "image_url": {"url": url}})
|
|
278
|
+
else:
|
|
279
|
+
parts.append({"type": "text", "text": str(block)})
|
|
280
|
+
if not parts:
|
|
281
|
+
return str(blocks)
|
|
282
|
+
if all(part["type"] == "text" for part in parts):
|
|
283
|
+
return "\n".join(str(part["text"]) for part in parts)
|
|
284
|
+
return parts
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
async def call_mcp(
|
|
288
|
+
servers: dict, dispatch: dict, name: str, arguments: dict
|
|
289
|
+
) -> str | list[dict]:
|
|
290
|
+
"""Call a tool on a fresh session per attempt — see `with_retry` for the replay semantics.
|
|
291
|
+
The result is converted outside the retry so a conversion failure fails once."""
|
|
292
|
+
server_name, raw = dispatch[name]
|
|
293
|
+
|
|
294
|
+
async def call():
|
|
295
|
+
async with mcp_session(servers[server_name]) as session:
|
|
296
|
+
return await session.call_tool(raw, arguments)
|
|
297
|
+
|
|
298
|
+
result = await with_retry(call)
|
|
299
|
+
return mcp_content_to_chat_content(result.content)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def parse_args() -> argparse.Namespace:
|
|
303
|
+
parser = argparse.ArgumentParser()
|
|
304
|
+
parser.add_argument("--base-url", required=True)
|
|
305
|
+
parser.add_argument("--api-key", required=True)
|
|
306
|
+
parser.add_argument("--model", required=True)
|
|
307
|
+
parser.add_argument("--state-dir", required=True)
|
|
308
|
+
parser.add_argument("--browser", default="chromium")
|
|
309
|
+
parser.add_argument("--cdp-url", default="")
|
|
310
|
+
parser.add_argument("--system-prompt", default="")
|
|
311
|
+
parser.add_argument("--prompt", default="")
|
|
312
|
+
parser.add_argument("--initial-messages-file", default="")
|
|
313
|
+
parser.add_argument("--mcp-config", default="")
|
|
314
|
+
return parser.parse_args()
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
async def main() -> None:
|
|
318
|
+
args = parse_args()
|
|
319
|
+
initial = []
|
|
320
|
+
if args.initial_messages_file:
|
|
321
|
+
path = Path(args.initial_messages_file)
|
|
322
|
+
payload = path.read_bytes()
|
|
323
|
+
path.unlink()
|
|
324
|
+
initial = json.loads(payload)
|
|
325
|
+
state_dir = Path(args.state_dir)
|
|
326
|
+
state_dir.mkdir(parents=True, exist_ok=True)
|
|
327
|
+
endpoint = (
|
|
328
|
+
ensure_chromium(state_dir) if args.browser == "chromium" else args.cdp_url
|
|
329
|
+
)
|
|
330
|
+
browser_env = {
|
|
331
|
+
**os.environ,
|
|
332
|
+
"BH_HOME": str(state_dir / "bh-home"),
|
|
333
|
+
"BH_TELEMETRY": "0",
|
|
334
|
+
(
|
|
335
|
+
"BU_CDP_WS" if urlsplit(endpoint).scheme in {"ws", "wss"} else "BU_CDP_URL"
|
|
336
|
+
): endpoint,
|
|
337
|
+
}
|
|
338
|
+
client = AsyncOpenAI(base_url=args.base_url, api_key=args.api_key)
|
|
339
|
+
config = json.loads(args.mcp_config or "{}")
|
|
340
|
+
tools = [BROWSER_TOOL]
|
|
341
|
+
reserved = {"browser"}
|
|
342
|
+
mcp_tools, dispatch, servers = (
|
|
343
|
+
await connect_mcp(config, reserved)
|
|
344
|
+
if config.get("mcpServers")
|
|
345
|
+
else ([], {}, {})
|
|
346
|
+
)
|
|
347
|
+
tools += mcp_tools
|
|
348
|
+
messages = (
|
|
349
|
+
[{"role": "system", "content": args.system_prompt}]
|
|
350
|
+
if args.system_prompt
|
|
351
|
+
else []
|
|
352
|
+
)
|
|
353
|
+
if initial:
|
|
354
|
+
messages.extend(initial)
|
|
355
|
+
elif args.prompt:
|
|
356
|
+
messages.append({"role": "user", "content": args.prompt})
|
|
357
|
+
while True:
|
|
358
|
+
message = await chat(client, args.model, messages, tools)
|
|
359
|
+
messages.append(message.model_dump(exclude_none=True))
|
|
360
|
+
if not message.tool_calls:
|
|
361
|
+
break
|
|
362
|
+
for call in message.tool_calls:
|
|
363
|
+
name = call.function.name
|
|
364
|
+
try:
|
|
365
|
+
tool_args = json.loads(call.function.arguments or "{}")
|
|
366
|
+
except json.JSONDecodeError as e:
|
|
367
|
+
messages.append(
|
|
368
|
+
{
|
|
369
|
+
"role": "tool",
|
|
370
|
+
"tool_call_id": call.id,
|
|
371
|
+
"content": f"error: invalid JSON in tool arguments ({e}); resend the call with valid JSON",
|
|
372
|
+
}
|
|
373
|
+
)
|
|
374
|
+
continue
|
|
375
|
+
# Valid JSON can still be a non-object (`[]`, `42`, `null`); the `.get(...)` calls
|
|
376
|
+
# below assume a dict, so reject anything else as a tool error rather than crashing.
|
|
377
|
+
if not isinstance(tool_args, dict):
|
|
378
|
+
messages.append(
|
|
379
|
+
{
|
|
380
|
+
"role": "tool",
|
|
381
|
+
"tool_call_id": call.id,
|
|
382
|
+
"content": f"error: tool arguments must be a JSON object, got {type(tool_args).__name__}; resend as an object",
|
|
383
|
+
}
|
|
384
|
+
)
|
|
385
|
+
continue
|
|
386
|
+
if name in dispatch:
|
|
387
|
+
content = await call_mcp(servers, dispatch, name, tool_args)
|
|
388
|
+
elif name == "browser":
|
|
389
|
+
content = await asyncio.to_thread(
|
|
390
|
+
run_browser,
|
|
391
|
+
tool_args.get("code", ""),
|
|
392
|
+
browser_env,
|
|
393
|
+
)
|
|
394
|
+
else:
|
|
395
|
+
content = f"error: unknown tool {name!r}"
|
|
396
|
+
messages.append(
|
|
397
|
+
{"role": "tool", "tool_call_id": call.id, "content": content}
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
if __name__ == "__main__":
|
|
402
|
+
asyncio.run(main())
|
|
@@ -22,7 +22,7 @@ from verifiers.v1.serve.types import (
|
|
|
22
22
|
RunRequest,
|
|
23
23
|
RunResponse,
|
|
24
24
|
)
|
|
25
|
-
from verifiers.v1.task import Task
|
|
25
|
+
from verifiers.v1.task import Task
|
|
26
26
|
from verifiers.v1.types import SamplingConfig
|
|
27
27
|
|
|
28
28
|
logger = logging.getLogger(__name__)
|
|
@@ -39,7 +39,7 @@ class EnvServer:
|
|
|
39
39
|
self.taskset_id = config.taskset.id
|
|
40
40
|
self.env = load_environment(config)
|
|
41
41
|
self.task_cls = type(self.env.taskset).task_type()
|
|
42
|
-
self.data_cls =
|
|
42
|
+
self.data_cls = self.task_cls.data_type()
|
|
43
43
|
# A dispatched task is its client-side model_dump(): a field excluded from
|
|
44
44
|
# serialization would vanish on the wire and rebuild silently defaulted, so
|
|
45
45
|
# refuse to serve such a taskset.
|