benchflow 0.5.3.dev908__tar.gz → 0.5.3.dev957__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 (414) hide show
  1. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/PKG-INFO +1 -1
  2. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/pyproject.toml +1 -1
  3. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/providers/litellm_bedrock_patch.py +5 -0
  4. benchflow-0.5.3.dev957/src/benchflow/providers/litellm_bedrock_preflight.py +181 -0
  5. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/providers/litellm_runtime.py +33 -1
  6. benchflow-0.5.3.dev957/src/benchflow/sandbox/_cache_reclaim.py +97 -0
  7. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/lockdown.py +8 -14
  8. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_litellm_hardening.py +187 -1
  9. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_litellm_runtime.py +28 -1
  10. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sandbox_hardening.py +106 -50
  11. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/.gitignore +0 -0
  12. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/CHANGELOG.md +0 -0
  13. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/LICENSE +0 -0
  14. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/README.md +0 -0
  15. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/__init__.py +0 -0
  16. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_dotenv.py +0 -0
  17. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_paths.py +0 -0
  18. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_run.py +0 -0
  19. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_types.py +0 -0
  20. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/__init__.py +0 -0
  21. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/benchmark_repos.py +0 -0
  22. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/config.py +0 -0
  23. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/evaluation_results.py +0 -0
  24. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/json_safe.py +0 -0
  25. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/learner_memory.py +0 -0
  26. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/result_metadata.py +0 -0
  27. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/reward_events.py +0 -0
  28. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/scoring.py +0 -0
  29. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/source_provenance.py +0 -0
  30. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/task_authoring.py +0 -0
  31. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/_utils/yaml_loader.py +0 -0
  32. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/acp/__init__.py +0 -0
  33. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/acp/client.py +0 -0
  34. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/acp/container_transport.py +0 -0
  35. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/acp/runtime.py +0 -0
  36. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/acp/session.py +0 -0
  37. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/acp/transport.py +0 -0
  38. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/acp/types.py +0 -0
  39. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/adapters/__init__.py +0 -0
  40. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/adapters/harbor.py +0 -0
  41. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/adapters/inbound.py +0 -0
  42. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/adapters/inspect_ai.py +0 -0
  43. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/adapters/ors.py +0 -0
  44. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/adapters/terminal_bench.py +0 -0
  45. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/__init__.py +0 -0
  46. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/codex_config.py +0 -0
  47. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/credentials.py +0 -0
  48. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/env.py +0 -0
  49. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/errors.py +0 -0
  50. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/harvey_lab_acp_shim.py +0 -0
  51. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/install.py +0 -0
  52. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/openclaw_acp_shim.py +0 -0
  53. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/pi_acp_launcher.py +0 -0
  54. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/protocol.py +0 -0
  55. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/providers.py +0 -0
  56. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/agents/registry.py +0 -0
  57. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/branch.py +0 -0
  58. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/cli/__init__.py +0 -0
  59. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/cli/continue_cmd.py +0 -0
  60. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/cli/main.py +0 -0
  61. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/cli/trace_import.py +0 -0
  62. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/compat/__init__.py +0 -0
  63. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/compat/harbor_registry.py +0 -0
  64. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/continue_run/__init__.py +0 -0
  65. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/continue_run/batch.py +0 -0
  66. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/continue_run/orchestrator.py +0 -0
  67. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/continue_run/replay_proxy.py +0 -0
  68. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/continue_run/run_folder.py +0 -0
  69. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/continue_run/sandbox_proxy.py +0 -0
  70. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/contracts/__init__.py +0 -0
  71. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/contracts/planes.py +0 -0
  72. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/contracts/user.py +0 -0
  73. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/demo_task/environment/Dockerfile +0 -0
  74. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/demo_task/instruction.md +0 -0
  75. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/demo_task/task.toml +0 -0
  76. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/demo_task/tests/test.sh +0 -0
  77. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/diagnostics.py +0 -0
  78. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/environment/__init__.py +0 -0
  79. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/environment/manifest.py +0 -0
  80. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/environment/manifest_env.py +0 -0
  81. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/environment/protocol.py +0 -0
  82. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/environment/readiness.py +0 -0
  83. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/eval_sharding.py +0 -0
  84. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/eval_worker.py +0 -0
  85. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/evaluation.py +0 -0
  86. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/experimental/__init__.py +0 -0
  87. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/experimental/mcp/__init__.py +0 -0
  88. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/experimental/mcp/hooks.py +0 -0
  89. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/experimental/mcp/reviewer_server.py +0 -0
  90. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/hosted_env.py +0 -0
  91. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/learner_skills.py +0 -0
  92. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/learner_store.py +0 -0
  93. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/metrics.py +0 -0
  94. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/models.py +0 -0
  95. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/monitor.py +0 -0
  96. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/providers/__init__.py +0 -0
  97. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/providers/litellm_config.py +0 -0
  98. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/providers/litellm_logging.py +0 -0
  99. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/providers/runtime.py +0 -0
  100. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/py.typed +0 -0
  101. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/README.md +0 -0
  102. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/__init__.py +0 -0
  103. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/builtins.py +0 -0
  104. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/events.py +0 -0
  105. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/file_readers.py +0 -0
  106. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/llm.py +0 -0
  107. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/memory_scorer.py +0 -0
  108. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/node.py +0 -0
  109. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/protocol.py +0 -0
  110. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/rubric.py +0 -0
  111. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/rubric_config.py +0 -0
  112. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rewards/validation.py +0 -0
  113. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rollout.py +0 -0
  114. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rollout_branch.py +0 -0
  115. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/rollout_planes.py +0 -0
  116. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/runtime.py +0 -0
  117. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/__init__.py +0 -0
  118. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/_base.py +0 -0
  119. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/_compose.py +0 -0
  120. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/_compose_files/docker-compose-base.yaml +0 -0
  121. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/_compose_files/docker-compose-build.yaml +0 -0
  122. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/_compose_files/docker-compose-no-network.yaml +0 -0
  123. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/_compose_files/docker-compose-prebuilt.yaml +0 -0
  124. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/_sdk_ops.py +0 -0
  125. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/daytona.py +0 -0
  126. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/docker.py +0 -0
  127. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/metadata.py +0 -0
  128. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/modal_impl.py +0 -0
  129. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/process.py +0 -0
  130. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/protocol.py +0 -0
  131. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/services.py +0 -0
  132. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/setup.py +0 -0
  133. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/snapshot.py +0 -0
  134. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sandbox/user.py +0 -0
  135. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/scenes.py +0 -0
  136. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/sdk.py +0 -0
  137. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/self_gen.py +0 -0
  138. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/skill_eval/__init__.py +0 -0
  139. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/skill_eval/_core.py +0 -0
  140. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/skill_eval/gepa_export.py +0 -0
  141. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/skill_eval/schema.py +0 -0
  142. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/skill_policy.py +0 -0
  143. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/skills.py +0 -0
  144. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/task/__init__.py +0 -0
  145. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/task/config.py +0 -0
  146. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/task/env.py +0 -0
  147. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/task/paths.py +0 -0
  148. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/task/task.py +0 -0
  149. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/task/verifier.py +0 -0
  150. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/templates/__init__.py +0 -0
  151. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/templates/judge.py.tmpl +0 -0
  152. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/templates/test.sh.tmpl +0 -0
  153. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/traces/__init__.py +0 -0
  154. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/traces/huggingface.py +0 -0
  155. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/traces/local.py +0 -0
  156. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/traces/models.py +0 -0
  157. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/traces/parsers.py +0 -0
  158. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/traces/task_gen.py +0 -0
  159. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/trajectories/__init__.py +0 -0
  160. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/trajectories/_capture.py +0 -0
  161. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/trajectories/export.py +0 -0
  162. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/trajectories/metrics.py +0 -0
  163. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/trajectories/otel.py +0 -0
  164. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/trajectories/tree.py +0 -0
  165. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/trajectories/types.py +0 -0
  166. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/trajectories/viewer.py +0 -0
  167. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/src/benchflow/usage_tracking.py +0 -0
  168. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/__init__.py +0 -0
  169. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/agents/__init__.py +0 -0
  170. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/agents/test_protocol.py +0 -0
  171. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/README.md +0 -0
  172. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/acp_smoke/environment/Dockerfile +0 -0
  173. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/acp_smoke/environment/docker-compose.yaml +0 -0
  174. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/acp_smoke/environment/skills/conformance-writer/SKILL.md +0 -0
  175. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/acp_smoke/instruction.md +0 -0
  176. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/acp_smoke/solution/solve.sh +0 -0
  177. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/acp_smoke/task.toml +0 -0
  178. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/acp_smoke/tests/test.sh +0 -0
  179. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/conformance-results.json +0 -0
  180. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/proof_multi_agent.py +0 -0
  181. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/proof_snapshot.py +0 -0
  182. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/run_conformance.py +0 -0
  183. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conformance/self_gen_smoke_skills/skill-creator/SKILL.md +0 -0
  184. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/conftest.py +0 -0
  185. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/continue_run/__init__.py +0 -0
  186. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/continue_run/_helpers.py +0 -0
  187. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/continue_run/test_batch.py +0 -0
  188. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/continue_run/test_orchestrator.py +0 -0
  189. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/continue_run/test_replay_proxy.py +0 -0
  190. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/continue_run/test_run_folder.py +0 -0
  191. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/environment/__init__.py +0 -0
  192. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/environment/test_chibench_manifest.py +0 -0
  193. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/environment/test_clawsbench_manifest.py +0 -0
  194. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/environment/test_manifest.py +0 -0
  195. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/environment/test_manifest_env.py +0 -0
  196. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/environment/test_protocol.py +0 -0
  197. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/environment/test_readiness.py +0 -0
  198. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/hello-world-task/environment/Dockerfile +0 -0
  199. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/hello-world-task/instruction.md +0 -0
  200. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/hello-world-task/solution/solve.sh +0 -0
  201. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/hello-world-task/task.toml +0 -0
  202. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/hello-world-task/tests/test.sh +0 -0
  203. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/terminal-bench-smoke-task/environment/Dockerfile +0 -0
  204. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/terminal-bench-smoke-task/instruction.md +0 -0
  205. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/terminal-bench-smoke-task/solution/solve.sh +0 -0
  206. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/terminal-bench-smoke-task/task.toml +0 -0
  207. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/terminal-bench-smoke-task/tests/test.sh +0 -0
  208. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/terminal-bench-smoke-task/tests/test_state.py +0 -0
  209. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/test_claude.sh +0 -0
  210. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/test_codex.sh +0 -0
  211. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/test_codex_custom_provider.sh +0 -0
  212. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/test_gemini.sh +0 -0
  213. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/test_openclaw.sh +0 -0
  214. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/traces/minimal-claude.jsonl +0 -0
  215. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/examples/traces/minimal-opentraces.jsonl +0 -0
  216. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/fixtures/mock_acp_agent.py +0 -0
  217. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/fixtures/mock_acp_agent_interleaved.py +0 -0
  218. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/fixtures/mock_acp_agent_multi_turn.py +0 -0
  219. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/fixtures/mock_openai_responses_server.py +0 -0
  220. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/check_adapter_evidence.py +0 -0
  221. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/check_hosted_env_evidence.py +0 -0
  222. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/check_results.py +0 -0
  223. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/check_skillsbench_harbor_parity.py +0 -0
  224. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/check_trace_to_task_evidence.py +0 -0
  225. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/configs/claude-agent-acp.yaml +0 -0
  226. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/configs/codex-acp.yaml +0 -0
  227. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/configs/gemini.yaml +0 -0
  228. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/configs/harvey-lab-harness.yaml +0 -0
  229. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/configs/openclaw.yaml +0 -0
  230. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/configs/opencode.yaml +0 -0
  231. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/configs/openhands.yaml +0 -0
  232. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/configs/pi-acp.yaml +0 -0
  233. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/run.sh +0 -0
  234. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/run_suite.py +0 -0
  235. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/integration/suites/release.yaml +0 -0
  236. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_acp.py +0 -0
  237. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_acp_capability_advertising.py +0 -0
  238. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_acp_model_config_dispatch.py +0 -0
  239. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_acp_pinned_protocol_guard.py +0 -0
  240. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_acp_setup_failure_propagation.py +0 -0
  241. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_adapter_scripts.py +0 -0
  242. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_adapters.py +0 -0
  243. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_agent_cli.py +0 -0
  244. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_agent_env_resolution.py +0 -0
  245. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_agent_gemini_defaults.py +0 -0
  246. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_agent_idle_timeout_cli.py +0 -0
  247. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_agent_model_decouple.py +0 -0
  248. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_agent_registry.py +0 -0
  249. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_agent_setup.py +0 -0
  250. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_agent_spec.py +0 -0
  251. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_base_install_imports.py +0 -0
  252. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_bedrock_thinking.py +0 -0
  253. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_branch.py +0 -0
  254. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_capture_trajectory.py +0 -0
  255. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_clawsbench_slice.py +0 -0
  256. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_cli_daytona.py +0 -0
  257. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_cli_docs_drift.py +0 -0
  258. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_cli_misc.py +0 -0
  259. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_compat_harbor_registry.py +0 -0
  260. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_config_redaction.py +0 -0
  261. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_connect_as_env.py +0 -0
  262. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_continuallearningbench_adapter.py +0 -0
  263. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_dashboard_credential_env_scrub.py +0 -0
  264. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_dashboard_daytona_key.py +0 -0
  265. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_dashboard_no_host_paths.py +0 -0
  266. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_dashboard_release_evidence.py +0 -0
  267. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_dashboard_roadmap.py +0 -0
  268. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_dashboard_symlink_ingestion.py +0 -0
  269. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_dashboard_sync.py +0 -0
  270. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_daytona_command_polling.py +0 -0
  271. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_daytona_litellm_runtime.py +0 -0
  272. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_daytona_status.py +0 -0
  273. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_docker_prune_scoping.py +0 -0
  274. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_docker_uploads.py +0 -0
  275. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_docs_examples.py +0 -0
  276. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_eng50_capabilities.py +0 -0
  277. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_env_setup.py +0 -0
  278. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_environment_manifest_controls.py +0 -0
  279. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_eval_filters_applied.py +0 -0
  280. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_eval_sharding.py +0 -0
  281. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_eval_single_task_summary.py +0 -0
  282. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_eval_source_provenance.py +0 -0
  283. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_eval_worker_retry.py +0 -0
  284. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_eval_zero_task_guard.py +0 -0
  285. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_evaluation_environment_manifest.py +0 -0
  286. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_exclude_tasks.py +0 -0
  287. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_experiments_status.py +0 -0
  288. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_harvey_lab_shim.py +0 -0
  289. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_hf_scores.py +0 -0
  290. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_hilbench_adapter.py +0 -0
  291. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_hosted_env.py +0 -0
  292. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_hosted_env_rollout_contract.py +0 -0
  293. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_inbound_adapter_manifest.py +0 -0
  294. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_inbound_adapters.py +0 -0
  295. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_integration_check_results.py +0 -0
  296. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_integration_run_suite.py +0 -0
  297. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_internet_policy.py +0 -0
  298. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_job.py +0 -0
  299. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_job_sequential_shared.py +0 -0
  300. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_job_sequential_shared_resume.py +0 -0
  301. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_judge_symlink_ingestion.py +0 -0
  302. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_learner_skills.py +0 -0
  303. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_learner_skills_traversal.py +0 -0
  304. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_learner_store.py +0 -0
  305. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_learner_store_persistence.py +0 -0
  306. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_litellm_config.py +0 -0
  307. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_litellm_logging.py +0 -0
  308. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_litellm_smoke.py +0 -0
  309. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_llm_judge.py +0 -0
  310. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_llm_judge_event_tags.py +0 -0
  311. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_llm_judge_verifier.py +0 -0
  312. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_memory_scorer.py +0 -0
  313. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_metrics.py +0 -0
  314. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_mock_openai_responses_server.py +0 -0
  315. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_monitor_scaffold.py +0 -0
  316. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_native_acp_usage.py +0 -0
  317. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_no_cross_provider_fallback.py +0 -0
  318. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_notification_order_real.py +0 -0
  319. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_oracle.py +0 -0
  320. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_oracle_chokepoint.py +0 -0
  321. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_paths_safe.py +0 -0
  322. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_paths_symlink_helpers.py +0 -0
  323. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_pi_acp_launcher.py +0 -0
  324. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_process.py +0 -0
  325. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_provider_auth_detection.py +0 -0
  326. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_providers.py +0 -0
  327. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_reexport.py +0 -0
  328. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_registry_invariants.py +0 -0
  329. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_release_version.py +0 -0
  330. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_resolve_env_helpers.py +0 -0
  331. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_reward_node.py +0 -0
  332. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_reward_unified_contract.py +0 -0
  333. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_rewards.py +0 -0
  334. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_rewards_jsonl.py +0 -0
  335. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_rollout_architecture.py +0 -0
  336. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_rollout_branch.py +0 -0
  337. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_rollout_config_path_coercion.py +0 -0
  338. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_rollout_environment.py +0 -0
  339. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_rollout_import_no_side_effects.py +0 -0
  340. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_rollout_on_ask_user_wiring.py +0 -0
  341. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_rollout_probe_sandbox_health.py +0 -0
  342. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_rollout_upload.py +0 -0
  343. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_rubric_config.py +0 -0
  344. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_runtime.py +0 -0
  345. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_runtime_config_wired.py +0 -0
  346. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_runtime_live_sandbox.py +0 -0
  347. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sandbox.py +0 -0
  348. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sandbox_exec_secret_handling.py +0 -0
  349. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sandbox_isolation_copy_traversal.py +0 -0
  350. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sandbox_multi_service.py +0 -0
  351. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sandbox_protocol.py +0 -0
  352. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sandbox_setup.py +0 -0
  353. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sandbox_snapshot_contract.py +0 -0
  354. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sandbox_upload_symlink.py +0 -0
  355. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sandbox_verifier_workspace.py +0 -0
  356. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_scene.py +0 -0
  357. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_scene_outbox_trial.py +0 -0
  358. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_scene_parallel_group.py +0 -0
  359. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_scene_result_aggregation.py +0 -0
  360. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_scoring.py +0 -0
  361. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sdk_internals.py +0 -0
  362. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_sdk_lockdown.py +0 -0
  363. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_self_gen_cli.py +0 -0
  364. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_self_gen_export_error_channel.py +0 -0
  365. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_self_gen_export_failures.py +0 -0
  366. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_self_gen_orchestration.py +0 -0
  367. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_session_request_permission_dispatch.py +0 -0
  368. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skill_eval.py +0 -0
  369. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skill_eval_dryrun.py +0 -0
  370. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skill_eval_integration.py +0 -0
  371. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skill_eval_sweep.py +0 -0
  372. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skill_eval_traversal.py +0 -0
  373. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skill_invocation_artifacts.py +0 -0
  374. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skill_policy.py +0 -0
  375. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skills.py +0 -0
  376. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skills_dir_agent_home_link.py +0 -0
  377. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skillsbench_harbor_parity.py +0 -0
  378. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skillsbench_harbor_run_suite.py +0 -0
  379. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_skillsbench_publish_scrub.py +0 -0
  380. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_smoke.py +0 -0
  381. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_subscription_auth.py +0 -0
  382. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_task_check_eval_consistency.py +0 -0
  383. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_task_config.py +0 -0
  384. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_task_download.py +0 -0
  385. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_tasks.py +0 -0
  386. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_token_usage_normalization.py +0 -0
  387. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_trace_import_cli.py +0 -0
  388. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_trace_task_gen_traversal.py +0 -0
  389. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_trace_to_task_evidence.py +0 -0
  390. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_traces_huggingface.py +0 -0
  391. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_traces_parsers.py +0 -0
  392. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_traces_task_gen.py +0 -0
  393. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_train_mode_artifact_emission.py +0 -0
  394. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_trajectory_integration.py +0 -0
  395. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_trajectory_streaming.py +0 -0
  396. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_trial_agent_timeout_verify.py +0 -0
  397. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_trial_install_agent_timeout.py +0 -0
  398. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_trial_litellm_runtime.py +0 -0
  399. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_usage_litellm.py +0 -0
  400. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_usage_required.py +0 -0
  401. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_usage_tracking.py +0 -0
  402. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_user.py +0 -0
  403. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_verifier_multi_container.py +0 -0
  404. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_verifier_output.py +0 -0
  405. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_verifier_output_freshness.py +0 -0
  406. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_verify.py +0 -0
  407. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_workflow_action_pinning.py +0 -0
  408. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/test_yaml_config.py +0 -0
  409. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/trajectories/__init__.py +0 -0
  410. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/trajectories/test_export.py +0 -0
  411. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/trajectories/test_export_nan_handling.py +0 -0
  412. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/trajectories/test_redaction.py +0 -0
  413. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/trajectories/test_step_granularity.py +0 -0
  414. {benchflow-0.5.3.dev908 → benchflow-0.5.3.dev957}/tests/trajectories/test_tree.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: benchflow
3
- Version: 0.5.3.dev908
3
+ Version: 0.5.3.dev957
4
4
  Summary: Multi-turn agent benchmarking with ACP — run any agent, any model, any provider.
5
5
  Project-URL: Homepage, https://github.com/benchflow-ai/benchflow
6
6
  Project-URL: Repository, https://github.com/benchflow-ai/benchflow
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "benchflow"
3
- version = "0.5.3.dev908"
3
+ version = "0.5.3.dev957"
4
4
  description = "Multi-turn agent benchmarking with ACP — run any agent, any model, any provider."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -70,6 +70,11 @@ def _patch_bedrock_effort() -> None:
70
70
  reasoning_effort = override
71
71
  return original(self, model, reasoning_effort, optional_params)
72
72
 
73
+ # Marker for the fail-closed startup preflight (#602): lets the runtime
74
+ # verify this override is installed without importing this module (which
75
+ # would itself apply the patches and mask a sitecustomize load failure).
76
+ setattr(handle, "__benchflow_bedrock_patch__", True) # noqa: B010
77
+
73
78
  setattr( # noqa: B010 - avoids static type narrowing on monkey-patched vendor API
74
79
  AmazonConverseConfig,
75
80
  "_handle_reasoning_effort_parameter",
@@ -0,0 +1,181 @@
1
+ """Fail-closed checks for BenchFlow's Bedrock Claude 4.8+ LiteLLM patch."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import shlex
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ from benchflow.providers.litellm_config import LiteLLMRoute
13
+
14
+
15
+ class BedrockPatchPreflightError(RuntimeError):
16
+ """Raised when the Bedrock patch cannot be proven active."""
17
+
18
+
19
+ # Behavioral preflight for the Bedrock Claude 4.8+ adaptive-thinking patch
20
+ # (#602). Runs in a fresh interpreter with the same env/PYTHONPATH as the proxy,
21
+ # so site loads the runtime dir's sitecustomize exactly like the proxy process
22
+ # does. It deliberately imports only litellm internals, never the patch module
23
+ # itself, which would apply the patches in-process and mask a load failure.
24
+ BEDROCK_PATCH_PREFLIGHT_SOURCE = """\
25
+ import sys
26
+
27
+ # Probe with a versioned Bedrock inference-profile ID: stock litellm 1.88.0rc1
28
+ # resolves the bare alias through its cost map, so only the versioned form
29
+ # discriminates patched from stock (#602).
30
+ PROBE = "us.anthropic.claude-opus-4-8-20251101-v1:0"
31
+
32
+ failures = []
33
+ try:
34
+ from litellm.llms.anthropic.chat.transformation import AnthropicConfig
35
+
36
+ if not AnthropicConfig._is_adaptive_thinking_model(PROBE):
37
+ failures.append(
38
+ "adaptive-thinking gate inactive: "
39
+ f"_is_adaptive_thinking_model({PROBE!r}) is False"
40
+ )
41
+ except Exception as exc: # noqa: BLE001 - report any import/shape drift
42
+ failures.append(f"anthropic transform unavailable: {exc}")
43
+ try:
44
+ from litellm.llms.bedrock.chat.converse_transformation import AmazonConverseConfig
45
+
46
+ handler = AmazonConverseConfig._handle_reasoning_effort_parameter
47
+ if not getattr(handler, "__benchflow_bedrock_patch__", False):
48
+ failures.append("reasoning-effort override inactive")
49
+ except Exception as exc: # noqa: BLE001 - report any import/shape drift
50
+ failures.append(f"bedrock converse transform unavailable: {exc}")
51
+ if failures:
52
+ print("; ".join(failures))
53
+ sys.exit(1)
54
+ """
55
+
56
+
57
+ def route_requires_bedrock_patch(route: LiteLLMRoute) -> bool:
58
+ """True when this resolved route depends on the Bedrock 4.8+ patch (#602)."""
59
+ return (
60
+ route.provider_name == "aws-bedrock"
61
+ and "reasoning_effort" in route.litellm_params
62
+ )
63
+
64
+
65
+ def _python_from_shebang(executable: Path, *, path_env: str | None) -> str | None:
66
+ try:
67
+ line = executable.open("rb").readline(4096).decode(errors="ignore").strip()
68
+ except OSError:
69
+ return None
70
+ if not line.startswith("#!"):
71
+ return None
72
+ try:
73
+ parts = shlex.split(line[2:].strip())
74
+ except ValueError:
75
+ return None
76
+ if not parts:
77
+ return None
78
+
79
+ command = parts[0]
80
+ if Path(command).name == "env":
81
+ args = parts[1:]
82
+ while args and args[0].startswith("-"):
83
+ args = args[1:]
84
+ if not args:
85
+ return None
86
+ command = args[0]
87
+
88
+ if not Path(command).name.startswith("python"):
89
+ return None
90
+ if "/" in command:
91
+ return command
92
+ return shutil.which(command, path=path_env) or command
93
+
94
+
95
+ def _host_python_for_litellm(
96
+ litellm_executable: str, *, env: dict[str, str] | None = None
97
+ ) -> str:
98
+ executable = Path(litellm_executable)
99
+ shebang_python = _python_from_shebang(
100
+ executable, path_env=env.get("PATH") if env else None
101
+ )
102
+ if shebang_python:
103
+ return shebang_python
104
+ sibling = executable.with_name("python")
105
+ if sibling.exists():
106
+ return str(sibling)
107
+ return sys.executable
108
+
109
+
110
+ def _failure_message(runtime: str, detail: str) -> str:
111
+ return (
112
+ "Bedrock Claude 4.8+ adaptive-thinking patch is NOT active in the "
113
+ f"{runtime} LiteLLM runtime: {detail[:2000]}. Failing closed before "
114
+ "agent launch (#602) - a silent fallback would send the legacy thinking "
115
+ "shape Bedrock rejects."
116
+ )
117
+
118
+
119
+ def preflight_host_bedrock_patch(
120
+ *,
121
+ env: dict[str, str],
122
+ litellm_executable: str,
123
+ ) -> None:
124
+ """Fail closed if the Bedrock 4.8+ patch is not active for the host proxy."""
125
+ try:
126
+ result = subprocess.run(
127
+ [
128
+ _host_python_for_litellm(litellm_executable, env=env),
129
+ "-c",
130
+ BEDROCK_PATCH_PREFLIGHT_SOURCE,
131
+ ],
132
+ env=env,
133
+ capture_output=True,
134
+ text=True,
135
+ timeout=120,
136
+ )
137
+ except Exception as exc:
138
+ raise BedrockPatchPreflightError(
139
+ _failure_message("host", f"preflight execution failed: {exc}")
140
+ ) from exc
141
+ if result.returncode != 0:
142
+ detail = (result.stdout or "").strip() or (result.stderr or "").strip()
143
+ raise BedrockPatchPreflightError(_failure_message("host", detail))
144
+
145
+
146
+ async def preflight_sandbox_bedrock_patch(
147
+ sandbox: Any,
148
+ *,
149
+ python: str,
150
+ runtime_dir: str,
151
+ preflight_path: str,
152
+ ) -> None:
153
+ """Fail closed if the Bedrock 4.8+ patch is not active in a sandbox proxy."""
154
+ command = (
155
+ f"PYTHONPATH={shlex.quote(runtime_dir)} "
156
+ f"{shlex.quote(python)} {shlex.quote(preflight_path)}"
157
+ )
158
+ try:
159
+ result = await sandbox.exec(command, timeout_sec=120)
160
+ except Exception as exc:
161
+ raise BedrockPatchPreflightError(
162
+ _failure_message("sandbox", f"preflight execution failed: {exc}")
163
+ ) from exc
164
+ if result.return_code != 0:
165
+ raise BedrockPatchPreflightError(
166
+ _failure_message(
167
+ "sandbox",
168
+ _exec_details("bedrock patch preflight", result),
169
+ )
170
+ )
171
+
172
+
173
+ def _exec_details(label: str, result: Any) -> str:
174
+ stdout = (getattr(result, "stdout", "") or "").strip()
175
+ stderr = (getattr(result, "stderr", "") or "").strip()
176
+ details = [f"{label} failed with exit code {getattr(result, 'return_code', '?')}"]
177
+ if stdout:
178
+ details.append(f"stdout: {stdout[:2000]}")
179
+ if stderr:
180
+ details.append(f"stderr: {stderr[:2000]}")
181
+ return "; ".join(details)
@@ -27,6 +27,13 @@ import yaml
27
27
  from benchflow.agents.codex_config import apply_codex_provider_config
28
28
  from benchflow.agents.env import uses_native_subscription_auth
29
29
  from benchflow.agents.registry import AGENTS
30
+ from benchflow.providers.litellm_bedrock_preflight import (
31
+ BEDROCK_PATCH_PREFLIGHT_SOURCE,
32
+ BedrockPatchPreflightError,
33
+ preflight_host_bedrock_patch,
34
+ preflight_sandbox_bedrock_patch,
35
+ route_requires_bedrock_patch,
36
+ )
30
37
  from benchflow.providers.litellm_config import (
31
38
  LITELLM_MASTER_KEY_ENV,
32
39
  LITELLM_MODEL_ALIAS_ENV,
@@ -447,12 +454,13 @@ async def _start_host_litellm(
447
454
  "BENCHFLOW_LITELLM_LOG_PATH": str(log_path),
448
455
  }
449
456
  )
457
+ litellm_executable = _host_litellm_executable()
450
458
  stdout = stdout_path.open("ab")
451
459
  stderr = stderr_path.open("ab")
452
460
  try:
453
461
  process = subprocess.Popen(
454
462
  [
455
- _host_litellm_executable(),
463
+ litellm_executable,
456
464
  "--config",
457
465
  str(config_path),
458
466
  "--host",
@@ -481,6 +489,14 @@ async def _start_host_litellm(
481
489
  )
482
490
  try:
483
491
  await _poll_host_health(runner)
492
+ if route_requires_bedrock_patch(route):
493
+ # Fail closed before the agent launches when the Bedrock 4.8+
494
+ # thinking patch did not activate (#602).
495
+ await asyncio.to_thread(
496
+ preflight_host_bedrock_patch,
497
+ env=env,
498
+ litellm_executable=litellm_executable,
499
+ )
484
500
  except BaseException:
485
501
  # A proxy that never became healthy still holds provider credentials and
486
502
  # an on-disk config with the master key — tear it down, don't leak it.
@@ -573,6 +589,7 @@ async def _upload_runtime_files_to_sandbox(
573
589
  "state": f"{runtime_dir}/state.json",
574
590
  "venv": f"{runtime_dir}/venv",
575
591
  "launch_config": f"{runtime_dir}/launch_config.json",
592
+ "preflight": f"{runtime_dir}/bedrock_patch_preflight.py",
576
593
  }
577
594
  result = await sandbox.exec(f"mkdir -p {shlex.quote(runtime_dir)}", timeout_sec=20)
578
595
  if result.return_code != 0:
@@ -591,6 +608,9 @@ async def _upload_runtime_files_to_sandbox(
591
608
  sandbox, f"import {_PATCH_MODULE}\n", paths["sitecustomize"], ".py"
592
609
  )
593
610
  await _upload_text(sandbox, _sandbox_launcher_source(), paths["launcher"], ".py")
611
+ await _upload_text(
612
+ sandbox, BEDROCK_PATCH_PREFLIGHT_SOURCE, paths["preflight"], ".py"
613
+ )
594
614
  return paths
595
615
 
596
616
 
@@ -765,6 +785,16 @@ async def _start_sandbox_litellm(
765
785
  port=port,
766
786
  stderr_path=paths["stderr"],
767
787
  )
788
+ if route_requires_bedrock_patch(route):
789
+ # Fail closed before the agent launches when the Bedrock 4.8+
790
+ # thinking patch did not activate (#602). On Daytona this proxy is
791
+ # the only protection — there is no host proxy to fall back to.
792
+ await preflight_sandbox_bedrock_patch(
793
+ sandbox,
794
+ python=python,
795
+ runtime_dir=runtime_dir,
796
+ preflight_path=paths["preflight"],
797
+ )
768
798
  except BaseException:
769
799
  # Never leak a half-started proxy (provider keys + master_key on disk).
770
800
  await _terminate_sandbox_litellm(
@@ -1054,6 +1084,8 @@ async def ensure_litellm_runtime(
1054
1084
  session_id=session_id,
1055
1085
  agent_name=agent,
1056
1086
  )
1087
+ except BedrockPatchPreflightError:
1088
+ raise
1057
1089
  except Exception as exc:
1058
1090
  return await _fallback_or_raise_for_unavailable_litellm(
1059
1091
  usage_cfg=usage_cfg,
@@ -0,0 +1,97 @@
1
+ """Pre-verifier cache reclaim command construction.
2
+
3
+ The sandbox cannot import benchflow internals, so the reclaim implementation is
4
+ an embedded Python snippet passed to ``python3 -c``. Keep it here instead of in
5
+ ``lockdown.py`` so the hardening orchestrator stays readable.
6
+ """
7
+
8
+ import shlex
9
+ from textwrap import dedent
10
+
11
+ # Symlink- and workspace-safe cache reclaim for #601.
12
+ #
13
+ # The previous shell form (`rm -rf "$u/.cache/uv" ...; rm -rf /tmp/uv-*`) could
14
+ # delete agent-visible state before scoring: `rm -rf` traverses intermediate
15
+ # symlinks (an agent-planted `~/.cache -> /app` turned the cache delete into
16
+ # `rm -rf /app/uv`), and the `/tmp/uv-*` glob matched a legitimate
17
+ # `/tmp/uv-workspace`. The textual `$WS`/`$u` guard saw none of that. Since
18
+ # ``restore_workspace`` defaults to False, nothing undid the damage.
19
+ #
20
+ # This snippet hardens every deletion candidate:
21
+ # - rejects any candidate with a symlink path component, including the final
22
+ # one, so agent-controlled parents can no longer redirect the delete;
23
+ # - resolves protected roots (workspace + /logs, covering /logs/artifacts and
24
+ # /logs/verifier) via realpath and skips candidates overlapping in either
25
+ # direction, applied uniformly to per-user caches, /tmp globs, and apt;
26
+ # - deletes with shutil.rmtree, which removes child symlinks without following
27
+ # them.
28
+ #
29
+ # argv[1] = active workspace (or /nonexistent). argv[2] = optional filesystem
30
+ # prefix, "" in production; tests pass a temp root so the exact production code
31
+ # runs hermetically against a fake filesystem.
32
+ #
33
+ # Fail-safe by construction: if python3 is unavailable the reclaim simply does
34
+ # not run (the trailing `true` swallows it). Losing best-effort ENOSPC mitigation
35
+ # is strictly better than deleting the wrong state.
36
+ RECLAIM_CACHES_PY = dedent(
37
+ """
38
+ import glob, os, shutil, sys
39
+
40
+ ws = sys.argv[1]
41
+ px = sys.argv[2] if len(sys.argv) > 2 else ''
42
+
43
+ def linked(path):
44
+ p = px or ''
45
+ for part in path[len(px):].strip('/').split('/'):
46
+ p = p + '/' + part
47
+ if os.path.islink(p):
48
+ return True
49
+ return False
50
+
51
+ protected = []
52
+ for root in (ws, px + '/logs'):
53
+ try:
54
+ if root and os.path.exists(root):
55
+ protected.append(os.path.realpath(root))
56
+ except OSError:
57
+ pass
58
+
59
+ def overlaps(path):
60
+ return any(
61
+ path == r or path.startswith(r + '/') or r.startswith(path + '/')
62
+ for r in protected
63
+ )
64
+
65
+ cands = [
66
+ u + '/.cache/' + name
67
+ for u in [px + '/root'] + sorted(glob.glob(px + '/home/*'))
68
+ for name in ('uv', 'pip', 'uv_build')
69
+ ]
70
+ cands += sorted(glob.glob(px + '/tmp/uv-*'))
71
+ cands += sorted(glob.glob(px + '/tmp/.uv-*'))
72
+ cands += sorted(glob.glob(px + '/var/cache/apt/archives/*.deb'))
73
+ for c in cands:
74
+ try:
75
+ if not os.path.lexists(c) or linked(c):
76
+ continue
77
+ # linked() proved no symlink components below the prefix, so
78
+ # realpath only normalizes the prefix itself - consistent with
79
+ # the realpath'd protected roots.
80
+ if overlaps(os.path.realpath(c)):
81
+ continue
82
+ if os.path.isdir(c):
83
+ shutil.rmtree(c, ignore_errors=True)
84
+ else:
85
+ os.remove(c)
86
+ except OSError:
87
+ pass
88
+ """
89
+ ).strip()
90
+
91
+
92
+ def build_reclaim_caches_cmd(workspace: str | None) -> str:
93
+ """Build the best-effort cache reclaim shell command."""
94
+ workspace_arg = shlex.quote(workspace) if workspace else "/nonexistent"
95
+ return (
96
+ f"python3 -c {shlex.quote(RECLAIM_CACHES_PY)} {workspace_arg} 2>/dev/null; true"
97
+ )
@@ -20,6 +20,7 @@ from pathlib import Path
20
20
  from typing import TYPE_CHECKING, Any
21
21
 
22
22
  from benchflow.agents.registry import get_sandbox_home_dirs
23
+ from benchflow.sandbox._cache_reclaim import build_reclaim_caches_cmd
23
24
 
24
25
  if TYPE_CHECKING:
25
26
  from benchflow.task import Task
@@ -877,22 +878,15 @@ async def harden_before_verify(
877
878
  # installed tools, or task assets — and a failure here never blocks the
878
879
  # verifier. Runs on `main` only, consistent with the hardening policy above.
879
880
  #
880
- # Workspace-aware: a task can legitimately use /root or /home/<user> as its
881
- # workspace (so "$u/.cache" would be workspace state the verifier must see
882
- # untouched). Skip any per-user cache that overlaps the active workspace in
883
- # either direction this matters because restore_workspace defaults to False,
884
- # so the later full restore does NOT run to undo a stray deletion.
885
- workspace_guard = shlex.quote(workspace) if workspace else "/nonexistent"
881
+ # Workspace-aware AND symlink-safe (#601): a task can legitimately use
882
+ # /root, /home/<user>, or /tmp/uv-* as its workspace, and an agent can
883
+ # plant `~/.cache -> /app` so a naive `rm -rf "$u/.cache/uv"` traverses
884
+ # into workspace/output state. The reclaim command rejects symlinked
885
+ # candidates and realpath-guards every deletion against the workspace and
886
+ # /logs this matters because restore_workspace defaults to False.
886
887
  try:
887
888
  await env.exec(
888
- f"WS={workspace_guard}; "
889
- "for u in /root /home/*; do "
890
- ' case "$WS" in "$u" | "$u"/*) continue ;; esac; '
891
- ' case "$u" in "$WS"/*) continue ;; esac; '
892
- ' rm -rf "$u/.cache/uv" "$u/.cache/pip" "$u/.cache/uv_build" 2>/dev/null; '
893
- "done; "
894
- "rm -rf /tmp/uv-* /tmp/.uv-* /var/cache/apt/archives/*.deb 2>/dev/null; "
895
- "true",
889
+ build_reclaim_caches_cmd(workspace),
896
890
  user="root",
897
891
  timeout_sec=30,
898
892
  )
@@ -13,6 +13,7 @@ from pathlib import Path
13
13
 
14
14
  import pytest
15
15
 
16
+ from benchflow.providers import litellm_bedrock_preflight as preflight_mod
16
17
  from benchflow.providers import litellm_runtime as runtime_mod
17
18
  from benchflow.providers.litellm_config import resolve_litellm_route
18
19
  from benchflow.providers.litellm_logging import (
@@ -242,10 +243,17 @@ _SUCCESS_LOG = json.dumps(
242
243
  class _FakeSandbox:
243
244
  """Drives the real sandbox-local LiteLLM launch/teardown code paths."""
244
245
 
245
- def __init__(self, *, fail_launch: bool = False, log_content: str = _SUCCESS_LOG):
246
+ def __init__(
247
+ self,
248
+ *,
249
+ fail_launch: bool = False,
250
+ fail_preflight: bool = False,
251
+ log_content: str = _SUCCESS_LOG,
252
+ ):
246
253
  self.uploaded: dict[str, str] = {}
247
254
  self.exec_calls: list[str] = []
248
255
  self.fail_launch = fail_launch
256
+ self.fail_preflight = fail_preflight
249
257
  self.log_content = log_content
250
258
  self._started = False
251
259
 
@@ -258,6 +266,10 @@ class _FakeSandbox:
258
266
  return _ExecResult(0, stdout=str(len(self.log_content)))
259
267
  if "urllib.request" in command:
260
268
  return _ExecResult(0)
269
+ if "bedrock_patch_preflight.py" in command:
270
+ if self.fail_preflight:
271
+ return _ExecResult(1, stdout="adaptive-thinking gate inactive")
272
+ return _ExecResult(0)
261
273
  if "launcher.py" in command:
262
274
  if self.fail_launch:
263
275
  return _ExecResult(1, stderr="boom")
@@ -410,6 +422,180 @@ def test_bedrock_patch_flags_cost_map_when_entry_present():
410
422
  assert flagged, "bedrock 4.8+ cost entries should be flagged adaptive-thinking"
411
423
 
412
424
 
425
+ # --------------------------------------------------------------------------- #
426
+ # Bedrock 4.8+ patch preflight fails closed (issue #602) #
427
+ # --------------------------------------------------------------------------- #
428
+
429
+ _BEDROCK_ENV = {"AWS_BEARER_TOKEN_BEDROCK": "tok", "AWS_REGION": "us-east-1"}
430
+
431
+
432
+ @pytest.mark.parametrize(
433
+ "model,required",
434
+ [
435
+ ("aws-bedrock/us.anthropic.claude-opus-4-8-20251101-v1:0", True),
436
+ ("aws-bedrock/eu.anthropic.claude-sonnet-4-9-20260301-v1:0", True),
437
+ ("aws-bedrock/us.anthropic.claude-opus-4-7-20251101-v1:0", False),
438
+ ],
439
+ )
440
+ def test_route_requires_bedrock_patch_gating(model, required):
441
+ """Guards PR #668's fail-closed gating for issue #602: only Bedrock Claude 4.8+
442
+ routes require the thinking patch; 4.7 and below stay best-effort."""
443
+ route = resolve_litellm_route(model, dict(_BEDROCK_ENV))
444
+ assert preflight_mod.route_requires_bedrock_patch(route) is required
445
+
446
+
447
+ def test_route_requires_bedrock_patch_ignores_non_bedrock_providers():
448
+ """Guards PR #668 / issue #602 scope: a 4.8 model on a non-Bedrock provider does not
449
+ trigger the fail-closed preflight (direct Anthropic handles 4.8 natively)."""
450
+ route = resolve_litellm_route(
451
+ "minimax/MiniMax-M3",
452
+ {"MINIMAX_API_KEY": "k", "MINIMAX_BASE_URL": "https://api.minimax.io/v1"},
453
+ )
454
+ assert preflight_mod.route_requires_bedrock_patch(route) is False
455
+
456
+
457
+ def test_host_bedrock_preflight_uses_litellm_shebang_python(tmp_path):
458
+ """Guards PR #668 against checking a different Python than the LiteLLM CLI
459
+ will actually run under when the executable is a script with a shebang."""
460
+ litellm = tmp_path / "litellm"
461
+ python = tmp_path / "tools" / "python"
462
+ python.parent.mkdir()
463
+ litellm.write_text(f"#!{python}\n")
464
+
465
+ assert preflight_mod._host_python_for_litellm(str(litellm)) == str(python)
466
+
467
+
468
+ def test_host_bedrock_preflight_resolves_env_shebang_with_proxy_path(tmp_path):
469
+ """Guards PR #668 against resolving `/usr/bin/env python*` with a different
470
+ PATH than the LiteLLM proxy receives."""
471
+ bindir = tmp_path / "bin"
472
+ bindir.mkdir()
473
+ python = bindir / "python3"
474
+ python.write_text("")
475
+ python.chmod(0o755)
476
+ litellm = tmp_path / "litellm"
477
+ litellm.write_text("#!/usr/bin/env python3\n")
478
+
479
+ assert preflight_mod._host_python_for_litellm(
480
+ str(litellm), env={"PATH": str(bindir)}
481
+ ) == str(python)
482
+
483
+
484
+ def test_bedrock_patch_preflight_passes_when_runtime_files_on_pythonpath(tmp_path):
485
+ """End-to-end happy path for the PR #668 preflight (issue #602): a fresh interpreter
486
+ with the runtime dir on PYTHONPATH loads sitecustomize -> patch module, so
487
+ the behavioral probe sees the patched litellm and exits 0."""
488
+ import os
489
+ import subprocess
490
+ import sys
491
+
492
+ runtime_mod._write_runtime_files(tmp_path, config={"model_list": []})
493
+ env = dict(os.environ)
494
+ env["PYTHONPATH"] = str(tmp_path)
495
+ result = subprocess.run(
496
+ [sys.executable, "-c", preflight_mod.BEDROCK_PATCH_PREFLIGHT_SOURCE],
497
+ env=env,
498
+ capture_output=True,
499
+ text=True,
500
+ timeout=120,
501
+ )
502
+ assert result.returncode == 0, result.stdout + result.stderr
503
+
504
+
505
+ def test_bedrock_patch_preflight_fails_closed_when_patch_not_loaded(tmp_path):
506
+ """THE regression test for issue #602's fail-open (fixed in PR #668): when the patch never
507
+ loads (sitecustomize missing from PYTHONPATH — the exact silent-failure
508
+ mode), the behavioral probe against stock litellm must exit non-zero so
509
+ setup fails before the agent launches, instead of regressing mid-task."""
510
+ import os
511
+ import subprocess
512
+ import sys
513
+
514
+ env = dict(os.environ)
515
+ env.pop("PYTHONPATH", None)
516
+ result = subprocess.run(
517
+ [sys.executable, "-c", preflight_mod.BEDROCK_PATCH_PREFLIGHT_SOURCE],
518
+ env=env,
519
+ capture_output=True,
520
+ text=True,
521
+ timeout=120,
522
+ )
523
+ assert result.returncode != 0
524
+ assert "inactive" in result.stdout
525
+
526
+
527
+ @pytest.mark.asyncio
528
+ async def test_sandbox_litellm_bedrock_route_runs_preflight():
529
+ """Guards PR #668 / issue #602 wiring: a Bedrock 4.8+ sandbox route must run the
530
+ patch preflight after health and succeed when the patch is active."""
531
+ route = resolve_litellm_route(
532
+ "aws-bedrock/us.anthropic.claude-opus-4-8-20251101-v1:0", dict(_BEDROCK_ENV)
533
+ )
534
+ sandbox = _FakeSandbox()
535
+
536
+ proc = await runtime_mod._start_sandbox_litellm(
537
+ sandbox=sandbox,
538
+ route=route,
539
+ master_key="sk-master",
540
+ agent_env=dict(_BEDROCK_ENV),
541
+ session_id="s",
542
+ agent_name="openhands",
543
+ )
544
+
545
+ preflights = [c for c in sandbox.exec_calls if "bedrock_patch_preflight.py" in c]
546
+ assert preflights, "Bedrock 4.8+ route must run the patch preflight"
547
+ assert proc.base_url == "http://127.0.0.1:45999"
548
+
549
+
550
+ @pytest.mark.asyncio
551
+ async def test_sandbox_litellm_bedrock_preflight_failure_fails_closed():
552
+ """THE sandbox fail-closed regression for issue #602 (PR #668): an inactive patch on
553
+ a Daytona Bedrock 4.8+ route must abort startup (RuntimeError) and tear the
554
+ half-started proxy down — never continue into the task fail-open."""
555
+ route = resolve_litellm_route(
556
+ "aws-bedrock/us.anthropic.claude-opus-4-8-20251101-v1:0", dict(_BEDROCK_ENV)
557
+ )
558
+ sandbox = _FakeSandbox(fail_preflight=True)
559
+
560
+ with pytest.raises(RuntimeError, match="NOT active"):
561
+ await runtime_mod._start_sandbox_litellm(
562
+ sandbox=sandbox,
563
+ route=route,
564
+ master_key="sk-master",
565
+ agent_env=dict(_BEDROCK_ENV),
566
+ session_id="s",
567
+ agent_name="openhands",
568
+ )
569
+
570
+ assert any(call.strip().startswith("rm -rf") for call in sandbox.exec_calls)
571
+
572
+
573
+ @pytest.mark.asyncio
574
+ async def test_sandbox_litellm_non_bedrock_route_skips_preflight():
575
+ """Guards PR #668 / issue #602 scope: non-Bedrock routes never run the preflight, so
576
+ a broken patch can not fail runs that do not depend on it."""
577
+ route = resolve_litellm_route(
578
+ "minimax/MiniMax-M3",
579
+ {"MINIMAX_API_KEY": "k", "MINIMAX_BASE_URL": "https://api.minimax.io/v1"},
580
+ )
581
+ sandbox = _FakeSandbox(fail_preflight=True) # would fail IF it ran
582
+
583
+ proc = await runtime_mod._start_sandbox_litellm(
584
+ sandbox=sandbox,
585
+ route=route,
586
+ master_key="sk-master",
587
+ agent_env={
588
+ "MINIMAX_API_KEY": "k",
589
+ "MINIMAX_BASE_URL": "https://api.minimax.io/v1",
590
+ },
591
+ session_id="s",
592
+ agent_name="openhands",
593
+ )
594
+
595
+ assert not [c for c in sandbox.exec_calls if "bedrock_patch_preflight.py" in c]
596
+ assert proc.base_url == "http://127.0.0.1:45999"
597
+
598
+
413
599
  # --------------------------------------------------------------------------- #
414
600
  # Embedded callback logger actually produces importable JSONL (no drift) #
415
601
  # --------------------------------------------------------------------------- #