agentinputlab 0.1.0a1__py3-none-any.whl

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 (469) hide show
  1. agentinputlab/__init__.py +28 -0
  2. agentinputlab/algorithms/__init__.py +6 -0
  3. agentinputlab/algorithms/acquire/__init__.py +145 -0
  4. agentinputlab/algorithms/acquire/adaptive_rag/__init__.py +43 -0
  5. agentinputlab/algorithms/acquire/adaptive_rag/replay.py +367 -0
  6. agentinputlab/algorithms/acquire/adaptive_rag/runtime.py +1202 -0
  7. agentinputlab/algorithms/acquire/adaptive_rag_common_support.py +542 -0
  8. agentinputlab/algorithms/acquire/hyde.py +296 -0
  9. agentinputlab/algorithms/acquire/hyde_controlled.py +200 -0
  10. agentinputlab/algorithms/acquire/hyde_external.py +148 -0
  11. agentinputlab/algorithms/acquire/ircot.py +28 -0
  12. agentinputlab/algorithms/acquire/ircot_common_support.py +478 -0
  13. agentinputlab/algorithms/acquire/ircot_native.py +355 -0
  14. agentinputlab/algorithms/acquire/ircot_replay.py +327 -0
  15. agentinputlab/algorithms/acquire/qrag/__init__.py +79 -0
  16. agentinputlab/algorithms/acquire/qrag/bridge.py +828 -0
  17. agentinputlab/algorithms/acquire/qrag/common_support.py +891 -0
  18. agentinputlab/algorithms/acquire/qrag/native_axis.py +71 -0
  19. agentinputlab/algorithms/acquire/qrag/reader_adapter.py +139 -0
  20. agentinputlab/algorithms/acquire/r2ag/__init__.py +57 -0
  21. agentinputlab/algorithms/acquire/r2ag/bridge.py +1312 -0
  22. agentinputlab/algorithms/acquire/r2ag/common_support.py +1029 -0
  23. agentinputlab/algorithms/acquire/r2ag/socket_runtime.py +255 -0
  24. agentinputlab/algorithms/clarify/__init__.py +61 -0
  25. agentinputlab/algorithms/clarify/_structured.py +64 -0
  26. agentinputlab/algorithms/clarify/active_task_disambiguation.py +371 -0
  27. agentinputlab/algorithms/clarify/ask_or_assume/__init__.py +17 -0
  28. agentinputlab/algorithms/clarify/ask_or_assume/monitor.py +410 -0
  29. agentinputlab/algorithms/clarify/future_turns.py +379 -0
  30. agentinputlab/algorithms/clarify/udcs.py +255 -0
  31. agentinputlab/algorithms/clarify/udcs_deterministic.py +196 -0
  32. agentinputlab/algorithms/curate/__init__.py +65 -0
  33. agentinputlab/algorithms/curate/acon/__init__.py +27 -0
  34. agentinputlab/algorithms/curate/acon/common.py +284 -0
  35. agentinputlab/algorithms/curate/acon/common_support.py +136 -0
  36. agentinputlab/algorithms/curate/acon/history_bridge.py +309 -0
  37. agentinputlab/algorithms/curate/acon/observation_bridge.py +290 -0
  38. agentinputlab/algorithms/curate/llmlingua/__init__.py +30 -0
  39. agentinputlab/algorithms/curate/llmlingua/adapters.py +537 -0
  40. agentinputlab/algorithms/curate/llmlingua/budget.py +48 -0
  41. agentinputlab/algorithms/curate/llmlingua/controlled.py +175 -0
  42. agentinputlab/algorithms/curate/llmlingua/multilingual.py +105 -0
  43. agentinputlab/algorithms/curate/llmlingua/span_map.py +167 -0
  44. agentinputlab/algorithms/curate/recomp/__init__.py +47 -0
  45. agentinputlab/algorithms/curate/recomp/external.py +1129 -0
  46. agentinputlab/algorithms/curate/recomp/selective.py +304 -0
  47. agentinputlab/algorithms/decompose/__init__.py +107 -0
  48. agentinputlab/algorithms/decompose/decomp/__init__.py +53 -0
  49. agentinputlab/algorithms/decompose/decomp/common_support.py +478 -0
  50. agentinputlab/algorithms/decompose/decomp/planner_component.py +199 -0
  51. agentinputlab/algorithms/decompose/decomp/worker_bridge.py +416 -0
  52. agentinputlab/algorithms/decompose/llm_compiler/__init__.py +35 -0
  53. agentinputlab/algorithms/decompose/llm_compiler/bridge.py +520 -0
  54. agentinputlab/algorithms/decompose/llm_compiler/common_support.py +504 -0
  55. agentinputlab/algorithms/decompose/plan_and_budget/__init__.py +43 -0
  56. agentinputlab/algorithms/decompose/plan_and_budget/cached_soft_budget.py +362 -0
  57. agentinputlab/algorithms/decompose/plan_and_budget/decomposer_component.py +107 -0
  58. agentinputlab/algorithms/decompose/plan_and_budget/full.py +205 -0
  59. agentinputlab/algorithms/decompose/plan_and_budget/hard_cap.py +246 -0
  60. agentinputlab/algorithms/decompose/plan_and_budget/regenerated_soft_budget.py +448 -0
  61. agentinputlab/algorithms/decompose/plan_and_solve/__init__.py +33 -0
  62. agentinputlab/algorithms/decompose/plan_and_solve/plan_component.py +192 -0
  63. agentinputlab/algorithms/decompose/plan_and_solve/ps_prompt.py +127 -0
  64. agentinputlab/algorithms/decompose/self_ask/__init__.py +27 -0
  65. agentinputlab/algorithms/decompose/self_ask/loop.py +362 -0
  66. agentinputlab/algorithms/decompose/self_ask/planner_component.py +117 -0
  67. agentinputlab/algorithms/reformulate/__init__.py +85 -0
  68. agentinputlab/algorithms/reformulate/infocqr/__init__.py +40 -0
  69. agentinputlab/algorithms/reformulate/infocqr/cache_replay.py +362 -0
  70. agentinputlab/algorithms/reformulate/infocqr/external.py +675 -0
  71. agentinputlab/algorithms/reformulate/infocqr/student.py +189 -0
  72. agentinputlab/algorithms/reformulate/query2doc/__init__.py +42 -0
  73. agentinputlab/algorithms/reformulate/query2doc/controlled_live.py +190 -0
  74. agentinputlab/algorithms/reformulate/query2doc/models.py +95 -0
  75. agentinputlab/algorithms/reformulate/query2doc/official_cached.py +335 -0
  76. agentinputlab/algorithms/reformulate/query2doc/querygym_bridge.py +223 -0
  77. agentinputlab/algorithms/reformulate/query2doc/querygym_runtime.py +326 -0
  78. agentinputlab/algorithms/reformulate/reformer/__init__.py +23 -0
  79. agentinputlab/algorithms/reformulate/reformer/external.py +417 -0
  80. agentinputlab/algorithms/reformulate/rrr.py +696 -0
  81. agentinputlab/annotation/__init__.py +5 -0
  82. agentinputlab/annotation/independent.py +428 -0
  83. agentinputlab/annotation/server.py +233 -0
  84. agentinputlab/annotation/static/app.js +121 -0
  85. agentinputlab/annotation/static/index.html +60 -0
  86. agentinputlab/annotation/static/review.css +2 -0
  87. agentinputlab/annotation/static/review.html +10 -0
  88. agentinputlab/annotation/static/review.js +11 -0
  89. agentinputlab/annotation/static/styles.css +55 -0
  90. agentinputlab/annotation/store.py +444 -0
  91. agentinputlab/api.py +368 -0
  92. agentinputlab/artifacts/__init__.py +15 -0
  93. agentinputlab/artifacts/json_file.py +104 -0
  94. agentinputlab/artifacts/manifest.py +98 -0
  95. agentinputlab/artifacts/store.py +157 -0
  96. agentinputlab/backends/__init__.py +98 -0
  97. agentinputlab/backends/embedding/__init__.py +25 -0
  98. agentinputlab/backends/embedding/base.py +145 -0
  99. agentinputlab/backends/embedding/callable.py +75 -0
  100. agentinputlab/backends/embedding/replay.py +129 -0
  101. agentinputlab/backends/llm/__init__.py +31 -0
  102. agentinputlab/backends/llm/base.py +149 -0
  103. agentinputlab/backends/llm/callable.py +108 -0
  104. agentinputlab/backends/llm/decomp_completion.py +88 -0
  105. agentinputlab/backends/llm/final_content_stop.py +72 -0
  106. agentinputlab/backends/llm/gpt_oss_final_channel.py +84 -0
  107. agentinputlab/backends/llm/openai_compatible.py +332 -0
  108. agentinputlab/backends/llm/transformers.py +171 -0
  109. agentinputlab/backends/retrieval/__init__.py +35 -0
  110. agentinputlab/backends/retrieval/base.py +50 -0
  111. agentinputlab/backends/retrieval/dense.py +777 -0
  112. agentinputlab/backends/retrieval/memory.py +119 -0
  113. agentinputlab/backends/retrieval/sqlite_fts.py +155 -0
  114. agentinputlab/backends/user/__init__.py +15 -0
  115. agentinputlab/backends/user/base.py +66 -0
  116. agentinputlab/backends/user/callable.py +54 -0
  117. agentinputlab/backends/user/replay.py +89 -0
  118. agentinputlab/backends/vector.py +38 -0
  119. agentinputlab/benchmarks/__init__.py +246 -0
  120. agentinputlab/benchmarks/acquisition.py +106 -0
  121. agentinputlab/benchmarks/ale.py +540 -0
  122. agentinputlab/benchmarks/appworld_ul.py +669 -0
  123. agentinputlab/benchmarks/assets.py +226 -0
  124. agentinputlab/benchmarks/base.py +68 -0
  125. agentinputlab/benchmarks/beir_archive.py +235 -0
  126. agentinputlab/benchmarks/beir_sample.py +269 -0
  127. agentinputlab/benchmarks/bfcl_native.py +245 -0
  128. agentinputlab/benchmarks/bfcl_v3.py +607 -0
  129. agentinputlab/benchmarks/cache.py +218 -0
  130. agentinputlab/benchmarks/clariq.py +203 -0
  131. agentinputlab/benchmarks/data/registry.json +321 -0
  132. agentinputlab/benchmarks/data/smoke_assets.json +511 -0
  133. agentinputlab/benchmarks/data/statebench_v0_8_1_task_ids.json +475 -0
  134. agentinputlab/benchmarks/data/toolsandbox_165848b_scenario_names.json +1 -0
  135. agentinputlab/benchmarks/execution.py +1111 -0
  136. agentinputlab/benchmarks/interactive.py +257 -0
  137. agentinputlab/benchmarks/ir_query.py +204 -0
  138. agentinputlab/benchmarks/longbench.py +203 -0
  139. agentinputlab/benchmarks/paired_replay.py +479 -0
  140. agentinputlab/benchmarks/preprocess.py +2313 -0
  141. agentinputlab/benchmarks/production.py +236 -0
  142. agentinputlab/benchmarks/qa.py +963 -0
  143. agentinputlab/benchmarks/registry.py +110 -0
  144. agentinputlab/benchmarks/retrieval.py +459 -0
  145. agentinputlab/benchmarks/runtime.py +509 -0
  146. agentinputlab/benchmarks/statebench.py +938 -0
  147. agentinputlab/benchmarks/tau3.py +725 -0
  148. agentinputlab/benchmarks/toolsandbox.py +626 -0
  149. agentinputlab/benchmarks/trec_dl_sample.py +263 -0
  150. agentinputlab/campaign.py +654 -0
  151. agentinputlab/campaign_runner.py +953 -0
  152. agentinputlab/cli/__init__.py +6 -0
  153. agentinputlab/cli/main.py +933 -0
  154. agentinputlab/connectors/__init__.py +46 -0
  155. agentinputlab/connectors/knowledge/__init__.py +4 -0
  156. agentinputlab/connectors/tools/__init__.py +30 -0
  157. agentinputlab/connectors/tools/base.py +57 -0
  158. agentinputlab/connectors/tools/mcp.py +222 -0
  159. agentinputlab/connectors/tools/memory.py +41 -0
  160. agentinputlab/connectors/tools/openapi.py +695 -0
  161. agentinputlab/connectors/tools/schema.py +102 -0
  162. agentinputlab/contracts/__init__.py +91 -0
  163. agentinputlab/contracts/availability.py +24 -0
  164. agentinputlab/contracts/dependency.py +58 -0
  165. agentinputlab/contracts/enums.py +82 -0
  166. agentinputlab/contracts/errors.py +63 -0
  167. agentinputlab/contracts/evidence.py +43 -0
  168. agentinputlab/contracts/intent.py +110 -0
  169. agentinputlab/contracts/lifecycle.py +164 -0
  170. agentinputlab/contracts/patch.py +167 -0
  171. agentinputlab/contracts/serialization.py +93 -0
  172. agentinputlab/contracts/state.py +127 -0
  173. agentinputlab/contracts/trace.py +59 -0
  174. agentinputlab/contracts/worker.py +42 -0
  175. agentinputlab/core/__init__.py +7 -0
  176. agentinputlab/data/__init__.py +32 -0
  177. agentinputlab/data/checksums.py +9 -0
  178. agentinputlab/data/downloader.py +235 -0
  179. agentinputlab/data/http.py +171 -0
  180. agentinputlab/data/index.py +21 -0
  181. agentinputlab/data/overlap.py +28 -0
  182. agentinputlab/data/preprocess.py +32 -0
  183. agentinputlab/data/storage.py +57 -0
  184. agentinputlab/data/trec_sample.py +427 -0
  185. agentinputlab/evaluation/__init__.py +5 -0
  186. agentinputlab/evaluation/outcomes.py +32 -0
  187. agentinputlab/experiments/__init__.py +278 -0
  188. agentinputlab/experiments/analysis.py +981 -0
  189. agentinputlab/experiments/artifacts.py +687 -0
  190. agentinputlab/experiments/automatic_measurement.py +678 -0
  191. agentinputlab/experiments/auxiliary_matrix.py +203 -0
  192. agentinputlab/experiments/bindings.py +430 -0
  193. agentinputlab/experiments/blueprints.py +147 -0
  194. agentinputlab/experiments/builders/__init__.py +45 -0
  195. agentinputlab/experiments/builders/executable_external_payload.py +423 -0
  196. agentinputlab/experiments/builders/external_process_arena.py +1018 -0
  197. agentinputlab/experiments/builders/registry_intervention.py +463 -0
  198. agentinputlab/experiments/cli.py +158 -0
  199. agentinputlab/experiments/controls.py +340 -0
  200. agentinputlab/experiments/driver_guard.py +205 -0
  201. agentinputlab/experiments/drivers/__init__.py +89 -0
  202. agentinputlab/experiments/drivers/external_arena.py +2908 -0
  203. agentinputlab/experiments/drivers/method_process.py +662 -0
  204. agentinputlab/experiments/drivers/parity_process.py +1484 -0
  205. agentinputlab/experiments/drivers/static_production.py +1574 -0
  206. agentinputlab/experiments/executor.py +448 -0
  207. agentinputlab/experiments/loader.py +605 -0
  208. agentinputlab/experiments/measurement.py +675 -0
  209. agentinputlab/experiments/paper_analysis.py +1818 -0
  210. agentinputlab/experiments/parity_identity.py +605 -0
  211. agentinputlab/experiments/plan.py +277 -0
  212. agentinputlab/experiments/production_builders.py +3739 -0
  213. agentinputlab/experiments/readiness.py +432 -0
  214. agentinputlab/experiments/schema.py +514 -0
  215. agentinputlab/experiments/secrets.py +177 -0
  216. agentinputlab/experiments/stateful_analysis.py +1738 -0
  217. agentinputlab/experiments/transfer_analysis.py +1316 -0
  218. agentinputlab/experiments/unseen_analysis.py +1025 -0
  219. agentinputlab/integrations/__init__.py +1 -0
  220. agentinputlab/integrations/action_space/__init__.py +1 -0
  221. agentinputlab/integrations/external_workers/__init__.py +76 -0
  222. agentinputlab/integrations/external_workers/ace.py +431 -0
  223. agentinputlab/integrations/external_workers/base.py +181 -0
  224. agentinputlab/integrations/external_workers/decomp_live.py +249 -0
  225. agentinputlab/integrations/external_workers/decomp_planner.py +30 -0
  226. agentinputlab/integrations/external_workers/infocqr_student.py +280 -0
  227. agentinputlab/integrations/external_workers/ircot.py +576 -0
  228. agentinputlab/integrations/external_workers/llmcompiler_live.py +360 -0
  229. agentinputlab/integrations/external_workers/longllmlingua.py +162 -0
  230. agentinputlab/integrations/external_workers/method.py +314 -0
  231. agentinputlab/integrations/external_workers/process.py +678 -0
  232. agentinputlab/integrations/external_workers/supervisor.py +1071 -0
  233. agentinputlab/integrations/full_architecture/__init__.py +1 -0
  234. agentinputlab/integrations/full_architecture/hyde.py +212 -0
  235. agentinputlab/integrations/full_architecture/plan_and_budget.py +188 -0
  236. agentinputlab/integrations/live_history.py +222 -0
  237. agentinputlab/integrations/prompt_optimization/__init__.py +1 -0
  238. agentinputlab/integrations/training/__init__.py +1 -0
  239. agentinputlab/metrics/__init__.py +50 -0
  240. agentinputlab/metrics/catalog.py +313 -0
  241. agentinputlab/metrics/harm.py +95 -0
  242. agentinputlab/metrics/paired.py +40 -0
  243. agentinputlab/metrics/qa.py +76 -0
  244. agentinputlab/metrics/text.py +33 -0
  245. agentinputlab/metrics/third_party.py +161 -0
  246. agentinputlab/models/__init__.py +4 -0
  247. agentinputlab/observability/__init__.py +56 -0
  248. agentinputlab/observability/budget.py +316 -0
  249. agentinputlab/observability/instrumentation.py +754 -0
  250. agentinputlab/observability/models.py +403 -0
  251. agentinputlab/observability/monitor.py +380 -0
  252. agentinputlab/optimizers/__init__.py +1 -0
  253. agentinputlab/optimizers/clarify/__init__.py +12 -0
  254. agentinputlab/optimizers/context/__init__.py +22 -0
  255. agentinputlab/optimizers/decompose/__init__.py +64 -0
  256. agentinputlab/optimizers/evidence/__init__.py +22 -0
  257. agentinputlab/optimizers/rewrite/__init__.py +30 -0
  258. agentinputlab/parity/__init__.py +5 -0
  259. agentinputlab/parity/base.py +206 -0
  260. agentinputlab/production_campaign.py +763 -0
  261. agentinputlab/py.typed +1 -0
  262. agentinputlab/recipes/__init__.py +333 -0
  263. agentinputlab/recipes/ace.py +418 -0
  264. agentinputlab/recipes/ace_bfcl.py +273 -0
  265. agentinputlab/recipes/ace_common_support.py +169 -0
  266. agentinputlab/recipes/ace_native_plan.py +322 -0
  267. agentinputlab/recipes/ace_online.py +711 -0
  268. agentinputlab/recipes/ace_retrieval.py +330 -0
  269. agentinputlab/recipes/ace_statebench.py +382 -0
  270. agentinputlab/recipes/ace_tau.py +463 -0
  271. agentinputlab/recipes/ace_toolsandbox.py +432 -0
  272. agentinputlab/recipes/acon_guideline.py +22 -0
  273. agentinputlab/recipes/adaptive_rag.py +822 -0
  274. agentinputlab/recipes/llmlingua2_inference.py +146 -0
  275. agentinputlab/recipes/llmlingua2_training.py +796 -0
  276. agentinputlab/recipes/mce.py +1486 -0
  277. agentinputlab/recipes/mce_final.py +335 -0
  278. agentinputlab/recipes/mce_text_fit.py +499 -0
  279. agentinputlab/recipes/mce_text_only.py +298 -0
  280. agentinputlab/recipes/qrag.py +729 -0
  281. agentinputlab/recipes/qrag_inference.py +364 -0
  282. agentinputlab/recipes/r2ag_features.py +236 -0
  283. agentinputlab/recipes/r2ag_inference.py +503 -0
  284. agentinputlab/recipes/r2ag_training.py +948 -0
  285. agentinputlab/recipes/recomp_abstractive.py +592 -0
  286. agentinputlab/recipes/recomp_extractive.py +525 -0
  287. agentinputlab/recipes/reformer.py +17 -0
  288. agentinputlab/recipes/rqrag.py +1516 -0
  289. agentinputlab/recipes/rqrag_common_support.py +193 -0
  290. agentinputlab/recipes/rqrag_completion.py +147 -0
  291. agentinputlab/recipes/skillopt.py +462 -0
  292. agentinputlab/recipes/skillopt_common_support.py +154 -0
  293. agentinputlab/recipes/skillopt_environment.py +165 -0
  294. agentinputlab/recipes/skillopt_environment_cli.py +5 -0
  295. agentinputlab/recipes/skillopt_retrieval.py +188 -0
  296. agentinputlab/recipes/smartsearch.py +897 -0
  297. agentinputlab/recipes/smartsearch_curriculum.py +283 -0
  298. agentinputlab/recipes/smartsearch_grpo_contracts.py +58 -0
  299. agentinputlab/recipes/smartsearch_grpo_data.py +314 -0
  300. agentinputlab/recipes/smartsearch_grpo_meter.py +324 -0
  301. agentinputlab/recipes/smartsearch_grpo_prefix.py +144 -0
  302. agentinputlab/recipes/smartsearch_grpo_rollout.py +119 -0
  303. agentinputlab/recipes/smartsearch_grpo_tools.py +364 -0
  304. agentinputlab/recipes/smartsearch_grpo_training.py +305 -0
  305. agentinputlab/recipes/smartsearch_grpo_transport.py +248 -0
  306. agentinputlab/recipes/smartsearch_grpo_worker.py +364 -0
  307. agentinputlab/recipes/smartsearch_inference.py +524 -0
  308. agentinputlab/recipes/smartsearch_native_data.py +172 -0
  309. agentinputlab/recipes/smartsearch_policy.py +616 -0
  310. agentinputlab/recipes/smartsearch_policy_worker.py +9 -0
  311. agentinputlab/recipes/smartsearch_sampling.py +232 -0
  312. agentinputlab/recipes/smartsearch_teacher.py +203 -0
  313. agentinputlab/recipes/smartsearch_training.py +265 -0
  314. agentinputlab/registry/__init__.py +46 -0
  315. agentinputlab/registry/beta.py +727 -0
  316. agentinputlab/registry/data/algorithms.json +1959 -0
  317. agentinputlab/registry/data/auxiliary_method_profiles.json +34 -0
  318. agentinputlab/registry/loader.py +100 -0
  319. agentinputlab/registry/result_manifest.py +184 -0
  320. agentinputlab/registry/runtime.py +195 -0
  321. agentinputlab/registry/schema.py +449 -0
  322. agentinputlab/runner/__init__.py +30 -0
  323. agentinputlab/runner/balance.py +248 -0
  324. agentinputlab/runner/cache.py +135 -0
  325. agentinputlab/runner/composite.py +130 -0
  326. agentinputlab/runner/engine.py +285 -0
  327. agentinputlab/runner/runtime_guard.py +268 -0
  328. agentinputlab/runner/worker.py +80 -0
  329. agentinputlab/runtime_bootstrap.py +288 -0
  330. agentinputlab/selectors/__init__.py +196 -0
  331. agentinputlab/selectors/advanced.py +1514 -0
  332. agentinputlab/selectors/artifacts.py +1087 -0
  333. agentinputlab/selectors/base.py +112 -0
  334. agentinputlab/selectors/campaigns.py +1893 -0
  335. agentinputlab/selectors/catalog.py +86 -0
  336. agentinputlab/selectors/discovery.py +1860 -0
  337. agentinputlab/selectors/evaluation.py +1348 -0
  338. agentinputlab/selectors/features.py +383 -0
  339. agentinputlab/selectors/learned.py +502 -0
  340. agentinputlab/selectors/no_op.py +28 -0
  341. agentinputlab/selectors/outcome_table.py +475 -0
  342. agentinputlab/selectors/producer.py +853 -0
  343. agentinputlab/selectors/rules.py +109 -0
  344. agentinputlab/selectors/runtime.py +420 -0
  345. agentinputlab/studies/__init__.py +16 -0
  346. agentinputlab/studies/design.py +165 -0
  347. agentinputlab/studies/paired.py +322 -0
  348. agentinputlab/studio/__init__.py +6 -0
  349. agentinputlab/studio/campaigns.py +819 -0
  350. agentinputlab/studio/engine.py +1408 -0
  351. agentinputlab/studio/model_backends.py +425 -0
  352. agentinputlab/studio/prepared.py +410 -0
  353. agentinputlab/studio/server.py +613 -0
  354. agentinputlab/studio/static/app.js +397 -0
  355. agentinputlab/studio/static/campaigns.html +175 -0
  356. agentinputlab/studio/static/campaigns.js +426 -0
  357. agentinputlab/studio/static/index.html +192 -0
  358. agentinputlab/studio/static/result.html +103 -0
  359. agentinputlab/studio/static/result.js +273 -0
  360. agentinputlab/studio/static/styles.css +467 -0
  361. agentinputlab-0.1.0a1.data/data/share/agentinputlab/CITATION.cff +22 -0
  362. agentinputlab-0.1.0a1.dist-info/METADATA +392 -0
  363. agentinputlab-0.1.0a1.dist-info/RECORD +469 -0
  364. agentinputlab-0.1.0a1.dist-info/WHEEL +5 -0
  365. agentinputlab-0.1.0a1.dist-info/entry_points.txt +6 -0
  366. agentinputlab-0.1.0a1.dist-info/licenses/LICENSE +21 -0
  367. agentinputlab-0.1.0a1.dist-info/licenses/NOTICE +31 -0
  368. agentinputlab-0.1.0a1.dist-info/licenses/THIRD_PARTY_NOTICES.md +94 -0
  369. agentinputlab-0.1.0a1.dist-info/top_level.txt +2 -0
  370. workers/README.md +94 -0
  371. workers/ace/README.md +261 -0
  372. workers/ace/__init__.py +1 -0
  373. workers/ace/compatibility_manifest.json +39 -0
  374. workers/ace/driver.py +1682 -0
  375. workers/acon/README.md +215 -0
  376. workers/acon/__init__.py +5 -0
  377. workers/acon/compatibility_manifest.json +93 -0
  378. workers/acon/driver.py +1859 -0
  379. workers/acon/fitted.py +395 -0
  380. workers/acon/guideline.py +470 -0
  381. workers/acon/guideline_source_manifest.json +20 -0
  382. workers/adaptive_rag/README.md +96 -0
  383. workers/adaptive_rag/__init__.py +15 -0
  384. workers/adaptive_rag/compatibility_manifest.json +61 -0
  385. workers/adaptive_rag/driver.py +1470 -0
  386. workers/adaptive_rag/fixture_runtime.py +163 -0
  387. workers/adaptive_rag/runtime.py +252 -0
  388. workers/ask_or_assume/README.md +124 -0
  389. workers/ask_or_assume/__init__.py +1 -0
  390. workers/ask_or_assume/compatibility_manifest.json +36 -0
  391. workers/ask_or_assume/driver.py +1227 -0
  392. workers/decomp/README.md +133 -0
  393. workers/decomp/UPSTREAM_LICENSE.Apache-2.0.txt +201 -0
  394. workers/decomp/__init__.py +5 -0
  395. workers/decomp/compatibility_manifest.json +205 -0
  396. workers/decomp/driver.py +1015 -0
  397. workers/decomp/live.py +137 -0
  398. workers/decomp/runtime.py +231 -0
  399. workers/infocqr/README.md +106 -0
  400. workers/infocqr/__init__.py +1 -0
  401. workers/infocqr/compatibility_manifest.json +84 -0
  402. workers/infocqr/driver.py +1766 -0
  403. workers/ircot/README.md +167 -0
  404. workers/ircot/__init__.py +7 -0
  405. workers/ircot/compatibility_manifest.json +121 -0
  406. workers/ircot/controlled.py +457 -0
  407. workers/ircot/driver.py +1373 -0
  408. workers/ircot/fixture_bindings.json +39 -0
  409. workers/ircot/fixture_config.json +48 -0
  410. workers/ircot/fixture_prompt.txt +2 -0
  411. workers/ircot/native_qa.py +398 -0
  412. workers/ircot/qa_compatibility_manifest.json +57 -0
  413. workers/ircot/runtime.py +97 -0
  414. workers/llmcompiler/README.md +160 -0
  415. workers/llmcompiler/__init__.py +1 -0
  416. workers/llmcompiler/compatibility_manifest.json +45 -0
  417. workers/llmcompiler/driver.py +1514 -0
  418. workers/llmcompiler/export_prompts.py +74 -0
  419. workers/llmcompiler/live.py +174 -0
  420. workers/llmcompiler/patch_manifest.json +147 -0
  421. workers/mce/README.md +198 -0
  422. workers/mce/__init__.py +29 -0
  423. workers/mce/compatibility_manifest.json +115 -0
  424. workers/mce/driver.py +2585 -0
  425. workers/mce/final_eval.py +173 -0
  426. workers/official_arenas/README.md +25 -0
  427. workers/official_arenas/__init__.py +1 -0
  428. workers/official_arenas/capture_records.py +110 -0
  429. workers/official_arenas/driver.py +619 -0
  430. workers/official_arenas/protocol.py +334 -0
  431. workers/official_arenas/providers/__init__.py +1 -0
  432. workers/official_arenas/providers/_live_history.py +228 -0
  433. workers/official_arenas/providers/_message_compat.py +77 -0
  434. workers/official_arenas/providers/appworld_ul.py +196 -0
  435. workers/official_arenas/providers/fixture.py +112 -0
  436. workers/official_arenas/providers/statebench.py +960 -0
  437. workers/official_arenas/providers/tau3.py +1672 -0
  438. workers/official_arenas/providers/tau_retail.py +586 -0
  439. workers/official_arenas/providers/toolsandbox.py +1321 -0
  440. workers/official_arenas/providers/tooltalk.py +699 -0
  441. workers/official_arenas/retail_capture.py +188 -0
  442. workers/official_arenas/retail_driver.py +275 -0
  443. workers/qrag/README.md +172 -0
  444. workers/qrag/__init__.py +1 -0
  445. workers/qrag/compatibility_manifest.json +64 -0
  446. workers/qrag/driver.py +673 -0
  447. workers/r2ag/README.md +154 -0
  448. workers/r2ag/__init__.py +5 -0
  449. workers/r2ag/compatibility_manifest.json +55 -0
  450. workers/r2ag/driver.py +1287 -0
  451. workers/r2ag/feature_schema.json +8 -0
  452. workers/r2ag/runtime.py +589 -0
  453. workers/recomp/README.md +120 -0
  454. workers/recomp/__init__.py +1 -0
  455. workers/recomp/compatibility_manifest.json +43 -0
  456. workers/recomp/driver.py +1653 -0
  457. workers/reformer/README.md +125 -0
  458. workers/reformer/__init__.py +1 -0
  459. workers/reformer/compatibility_manifest.json +68 -0
  460. workers/reformer/driver.py +1459 -0
  461. workers/reformer/induction.py +457 -0
  462. workers/rrr/README.md +126 -0
  463. workers/rrr/__init__.py +1 -0
  464. workers/rrr/compatibility_manifest.json +57 -0
  465. workers/rrr/driver.py +1133 -0
  466. workers/smartsearch/README.md +331 -0
  467. workers/smartsearch/__init__.py +1 -0
  468. workers/smartsearch/compatibility_manifest.json +41 -0
  469. workers/smartsearch/driver.py +1643 -0
@@ -0,0 +1,662 @@
1
+ """Shared exact-SHA process driver for stateless method-versus-``NO_OP`` discovery.
2
+
3
+ The benchmark-specific adapter remains a small committed worker script, while
4
+ the experiment driver, process supervision, identity receipts, unit preflight,
5
+ and persistence guard are shared across stateless profile kinds. Stateful
6
+ ``clarify`` and ``composite`` discovery must use the atomic external-arena
7
+ driver instead.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import hashlib
13
+ import json
14
+ import os
15
+ from collections.abc import Mapping, Sequence
16
+ from dataclasses import dataclass
17
+ from pathlib import Path
18
+ from typing import Any
19
+
20
+ from agentinputlab.contracts.errors import (
21
+ ArtifactError,
22
+ ExternalDependencyError,
23
+ ValidationError,
24
+ )
25
+ from agentinputlab.contracts.serialization import (
26
+ canonical_json,
27
+ content_hash,
28
+ freeze_mapping,
29
+ )
30
+ from agentinputlab.experiments.bindings import resolve_frozen_binding_receipt
31
+ from agentinputlab.experiments.executor import ExperimentCellResult
32
+ from agentinputlab.experiments.parity_identity import (
33
+ HOST_EXECUTION_RECEIPT_PROTOCOL,
34
+ )
35
+ from agentinputlab.experiments.plan import ExperimentCell
36
+ from agentinputlab.experiments.schema import (
37
+ ExperimentManifest,
38
+ ExperimentStage,
39
+ require_sha256,
40
+ )
41
+ from agentinputlab.experiments.secrets import (
42
+ environment_secret_values,
43
+ redact_secret_text,
44
+ require_secret_free,
45
+ )
46
+ from agentinputlab.integrations.external_workers.supervisor import (
47
+ LocalSubprocessSupervisor,
48
+ SupervisedWorkerError,
49
+ WorkerSupervisor,
50
+ worker_supervisor_from_environment,
51
+ )
52
+ from agentinputlab.observability import ResourceLimits, ResourceReceipt
53
+
54
+ from .parity_process import (
55
+ RESPONSE_PROTOCOL,
56
+ LockedProcessWorker,
57
+ attest_locked_process_worker,
58
+ build_host_execution_receipt,
59
+ execute_locked_process_worker,
60
+ load_locked_process_worker,
61
+ locked_process_worker_environment,
62
+ parse_locked_process_response,
63
+ )
64
+
65
+ CONFIG_PATH_ENV = "AILAB_METHOD_PROCESS_CONFIG"
66
+ CONFIG_SHA256_ENV = "AILAB_METHOD_PROCESS_CONFIG_SHA256"
67
+ UNIT_INVENTORY_ENV = "AILAB_METHOD_DISCOVERY_UNITS"
68
+ UNIT_INVENTORY_SHA256_ENV = "AILAB_METHOD_DISCOVERY_UNITS_SHA256"
69
+ DRIVER_PROTOCOL = "agentinputlab.method-process-driver.v1"
70
+ REQUEST_PROTOCOL = "agentinputlab.method-process-request.v1"
71
+
72
+ _ARM_IDS = ("no_op", "candidate")
73
+ _CANDIDATE_CHECKOUT_ENV = "AILAB_CANDIDATE_CHECKOUT"
74
+ _BASE_PASSTHROUGH_ENVIRONMENTS = (
75
+ "AILAB_PREPARED_DATA_ROOT",
76
+ "AILAB_METHOD_CHECKOUT",
77
+ "AILAB_METHOD_ASSET_MANIFEST",
78
+ "AILAB_MODEL_CONFIG",
79
+ "AILAB_RETRIEVER_CONFIG",
80
+ )
81
+ _WORKER_FIELDS = frozenset(
82
+ {
83
+ "checkout_environment",
84
+ "expected_checkout_revision",
85
+ "expected_checkout_tree",
86
+ "adapter_checkout_environment",
87
+ "expected_adapter_checkout_revision",
88
+ "expected_adapter_checkout_tree",
89
+ "executable_path",
90
+ "executable_sha256",
91
+ "entrypoint",
92
+ "entrypoint_sha256",
93
+ "arguments",
94
+ "pass_environment",
95
+ "request_parameters",
96
+ }
97
+ )
98
+ _CONFIG_FIELDS = frozenset(
99
+ {
100
+ "schema_version",
101
+ "protocol",
102
+ "method_id",
103
+ "candidate_release_id",
104
+ "workers",
105
+ "resource_limits",
106
+ "pipe_limits",
107
+ "shared_request_parameters",
108
+ }
109
+ )
110
+ _LIMIT_FIELDS = frozenset(
111
+ {
112
+ "wall_timeout_seconds",
113
+ "memory_bytes",
114
+ "cpus",
115
+ "pids_limit",
116
+ }
117
+ )
118
+ _PIPE_FIELDS = frozenset(
119
+ {
120
+ "max_input_bytes",
121
+ "max_stdout_bytes",
122
+ "max_stderr_bytes",
123
+ }
124
+ )
125
+
126
+
127
+ @dataclass(frozen=True, slots=True)
128
+ class _Configuration:
129
+ method_id: str
130
+ candidate_release_id: str
131
+ workers: Mapping[str, LockedProcessWorker]
132
+ resource_limits: ResourceLimits
133
+ pipe_limits: Mapping[str, int]
134
+ shared_request_parameters: Mapping[str, Any]
135
+ config_sha256: str
136
+
137
+
138
+ class MethodProcessExperimentDriver:
139
+ """Run ``NO_OP`` and one method release through locked JSON processes."""
140
+
141
+ def __init__(
142
+ self,
143
+ configuration: _Configuration,
144
+ *,
145
+ environment: Mapping[str, str],
146
+ supervisor: WorkerSupervisor | None = None,
147
+ ) -> None:
148
+ self._configuration = configuration
149
+ self._environment = dict(environment)
150
+ self._supervisor = supervisor or LocalSubprocessSupervisor()
151
+ if not isinstance(self._supervisor, WorkerSupervisor):
152
+ raise TypeError("method-process supervisor must implement WorkerSupervisor")
153
+ self._manifest_hash: str | None = None
154
+ self._binding_receipt_hash: str | None = None
155
+ self._worker_states: Mapping[str, Mapping[str, Any]] = freeze_mapping({})
156
+ self._checkout_binding_hashes: Mapping[str, str] = freeze_mapping({})
157
+ self._adapter_checkout_binding_hashes: Mapping[str, str] = freeze_mapping({})
158
+ self._unit_ids: frozenset[str] = frozenset()
159
+ self._fingerprint = freeze_mapping(self._build_fingerprint())
160
+
161
+ @classmethod
162
+ def from_config(
163
+ cls,
164
+ path: str | Path,
165
+ *,
166
+ expected_sha256: str,
167
+ environment: Mapping[str, str] | None = None,
168
+ supervisor: WorkerSupervisor | None = None,
169
+ ) -> MethodProcessExperimentDriver:
170
+ env = dict(os.environ if environment is None else environment)
171
+ return cls(
172
+ _load_configuration(
173
+ Path(path),
174
+ expected_sha256=expected_sha256,
175
+ environment=env,
176
+ ),
177
+ environment=env,
178
+ supervisor=supervisor,
179
+ )
180
+
181
+ def fingerprint(self) -> Mapping[str, Any]:
182
+ return self._fingerprint
183
+
184
+ def preflight(self, manifest: ExperimentManifest) -> Sequence[str]:
185
+ blockers: list[str] = []
186
+ if manifest.stage is not ExperimentStage.DISCOVERY:
187
+ blockers.append("method-process driver requires stage=discovery")
188
+ if manifest.metadata.get("requires_atomic_external_replay") is True:
189
+ blockers.append(
190
+ "method-process driver cannot execute stateful discovery; "
191
+ "use the external-arena atomic replay driver"
192
+ )
193
+ if manifest.metadata.get("method_id") != self._configuration.method_id:
194
+ blockers.append("method-process config method_id differs from manifest")
195
+ if (
196
+ manifest.metadata.get("candidate_release_id")
197
+ != self._configuration.candidate_release_id
198
+ ):
199
+ blockers.append("method-process candidate release differs from manifest")
200
+ if set(arm.arm_id for arm in manifest.arms) != set(_ARM_IDS):
201
+ blockers.append("method-process driver requires exact no_op and candidate arms")
202
+ candidate = next(
203
+ (arm for arm in manifest.arms if arm.arm_id == "candidate"),
204
+ None,
205
+ )
206
+ if candidate is None or candidate.release_id != self._configuration.candidate_release_id:
207
+ blockers.append("method-process candidate arm differs from config")
208
+ if isinstance(self._supervisor, LocalSubprocessSupervisor) and any(
209
+ value is not None
210
+ for value in (
211
+ self._configuration.resource_limits.memory_bytes,
212
+ self._configuration.resource_limits.cpus,
213
+ self._configuration.resource_limits.pids_limit,
214
+ )
215
+ ):
216
+ blockers.append(
217
+ "local method-process supervision supports hard wall/pipe limits only; "
218
+ "use a container supervisor for memory/CPU/PID limits"
219
+ )
220
+ pass_names = self._manifest_pass_environment(manifest)
221
+ for worker in self._configuration.workers.values():
222
+ missing = sorted(
223
+ name
224
+ for name in (*pass_names, *worker.pass_environment)
225
+ if not self._environment.get(name)
226
+ )
227
+ if missing:
228
+ blockers.append(
229
+ f"method-process {worker.arm_id} missing environments: " + ", ".join(missing)
230
+ )
231
+ try:
232
+ unit_ids = _load_unit_inventory(self._environment)
233
+ except (ArtifactError, ValidationError) as exc:
234
+ blockers.append(redact_secret_text(str(exc)))
235
+ unit_ids = ()
236
+ if blockers:
237
+ return tuple(blockers)
238
+ try:
239
+ worker_states = {
240
+ arm_id: attest_locked_process_worker(worker)
241
+ for arm_id, worker in self._configuration.workers.items()
242
+ }
243
+ binding_receipt = resolve_frozen_binding_receipt(
244
+ manifest,
245
+ environment=self._environment,
246
+ )
247
+ checkout_hashes = {
248
+ arm_id: binding_receipt.binding(
249
+ worker.checkout_environment,
250
+ kind="directory_env",
251
+ ).binding_hash
252
+ for arm_id, worker in self._configuration.workers.items()
253
+ }
254
+ adapter_checkout_hashes = {
255
+ arm_id: binding_receipt.binding(
256
+ worker.adapter_checkout_environment,
257
+ kind="directory_env",
258
+ ).binding_hash
259
+ for arm_id, worker in self._configuration.workers.items()
260
+ }
261
+ except (ArtifactError, ExternalDependencyError, ValidationError) as exc:
262
+ return (redact_secret_text(str(exc)),)
263
+ self._manifest_hash = manifest.manifest_hash
264
+ self._binding_receipt_hash = binding_receipt.receipt_hash
265
+ self._worker_states = freeze_mapping(worker_states)
266
+ self._checkout_binding_hashes = freeze_mapping(checkout_hashes)
267
+ self._adapter_checkout_binding_hashes = freeze_mapping(adapter_checkout_hashes)
268
+ self._unit_ids = frozenset(unit_ids)
269
+ return ()
270
+
271
+ def preflight_units(
272
+ self,
273
+ manifest: ExperimentManifest,
274
+ resolved_units: Mapping[str, Sequence[str]],
275
+ ) -> Sequence[str]:
276
+ """Prove the plan is exactly the checksum-locked discovery inventory."""
277
+
278
+ if self._manifest_hash != manifest.manifest_hash or not self._unit_ids:
279
+ return ("unit inventory validation requires a successful driver preflight",)
280
+ expected_keys = {f"{target.cell_id}:{target.split}" for target in manifest.benchmarks}
281
+ if set(resolved_units) != expected_keys:
282
+ return ("resolved unit inventories differ from method discovery targets",)
283
+ observed: set[str] = set()
284
+ for key in expected_keys:
285
+ values = tuple(resolved_units[key])
286
+ if len(values) != len(set(values)):
287
+ return (f"{key}: resolved discovery units contain duplicates",)
288
+ observed.update(values)
289
+ missing = sorted(self._unit_ids - observed)
290
+ extra = sorted(observed - self._unit_ids)
291
+ if missing or extra:
292
+ return (
293
+ "resolved discovery units differ from checksum-locked inventory; "
294
+ f"missing={missing[:5]}, extra={extra[:5]}",
295
+ )
296
+ return ()
297
+
298
+ def execute_cell(
299
+ self,
300
+ manifest: ExperimentManifest,
301
+ cell: ExperimentCell,
302
+ ) -> ExperimentCellResult:
303
+ self._require_preflight(manifest, cell)
304
+ outcomes: list[dict[str, Any]] = []
305
+ receipts: list[ResourceReceipt] = []
306
+ for arm_id in cell.arm_ids:
307
+ worker = self._configuration.workers[arm_id]
308
+ request = self._request(manifest, cell, arm_id)
309
+ passed_names = (
310
+ *self._manifest_pass_environment(manifest),
311
+ *worker.pass_environment,
312
+ )
313
+ environment = locked_process_worker_environment(
314
+ worker,
315
+ environment=self._environment,
316
+ pass_environment=passed_names,
317
+ request_protocol=REQUEST_PROTOCOL,
318
+ )
319
+ process = execute_locked_process_worker(
320
+ worker,
321
+ supervisor=self._supervisor,
322
+ input_text=canonical_json(request) + "\n",
323
+ limits=self._configuration.resource_limits,
324
+ pipe_limits=self._configuration.pipe_limits,
325
+ environment=environment,
326
+ process_name=f"method-process-{arm_id}",
327
+ config_sha256=self._configuration.config_sha256,
328
+ expected_worker_state=self._worker_states[arm_id],
329
+ )
330
+ passed_values = environment_secret_values(
331
+ self._environment,
332
+ passed_names,
333
+ )
334
+ if process.returncode != 0:
335
+ message = redact_secret_text(
336
+ process.stderr.strip() or "worker exited non-zero",
337
+ secret_values=passed_values,
338
+ )
339
+ raise SupervisedWorkerError(
340
+ f"method-process {arm_id} failed: {message}",
341
+ resource_receipt=process.resource_receipt,
342
+ )
343
+ response = parse_locked_process_response(
344
+ process,
345
+ expected_request_hash=request["request_hash"],
346
+ secret_values=passed_values,
347
+ )
348
+ host_receipt = build_host_execution_receipt(
349
+ config_sha256=self._configuration.config_sha256,
350
+ manifest=manifest,
351
+ cell=cell,
352
+ worker=worker,
353
+ request=request,
354
+ process=process,
355
+ checkout_binding_hash=self._checkout_binding_hashes[arm_id],
356
+ adapter_checkout_binding_hash=(self._adapter_checkout_binding_hashes[arm_id]),
357
+ )
358
+ outcome: dict[str, Any] = {
359
+ "arm_id": arm_id,
360
+ "status": response["status"],
361
+ "request_hash": response["request_hash"],
362
+ "usage": response["usage"],
363
+ "output": response["output"],
364
+ "host_execution_receipt": host_receipt,
365
+ }
366
+ if response["status"] == "succeeded":
367
+ outcome["metrics"] = response["metrics"]
368
+ else:
369
+ outcome["failure"] = response["failure"]
370
+ outcomes.append(outcome)
371
+ receipts.append(process.resource_receipt)
372
+ return ExperimentCellResult(
373
+ cell_id=cell.cell_id,
374
+ status="succeeded",
375
+ payload={
376
+ "frozen_binding_receipt_hash": self._binding_receipt_hash,
377
+ "host_execution_receipt_protocol": HOST_EXECUTION_RECEIPT_PROTOCOL,
378
+ "arms": outcomes,
379
+ },
380
+ resource_receipts=tuple(receipts),
381
+ )
382
+
383
+ def _build_fingerprint(self) -> dict[str, Any]:
384
+ bindings = {
385
+ arm_id: {
386
+ "checkout_environment": worker.checkout_environment,
387
+ "checkout": worker.checkout_identity.to_dict(),
388
+ "adapter_checkout_environment": worker.adapter_checkout_environment,
389
+ "adapter_checkout": worker.adapter_checkout_identity.to_dict(),
390
+ "command": worker.command_identity.to_dict(),
391
+ }
392
+ for arm_id, worker in self._configuration.workers.items()
393
+ }
394
+ return {
395
+ "schema_version": 1,
396
+ "driver": DRIVER_PROTOCOL,
397
+ "config_sha256": self._configuration.config_sha256,
398
+ "method_id": self._configuration.method_id,
399
+ "candidate_release_id": self._configuration.candidate_release_id,
400
+ "execution_receipt_protocol": HOST_EXECUTION_RECEIPT_PROTOCOL,
401
+ "host_process_bindings": bindings,
402
+ "resource_limits": self._configuration.resource_limits.as_dict(),
403
+ "pipe_limits": dict(self._configuration.pipe_limits),
404
+ "supervisor": dict(self._supervisor.fingerprint()),
405
+ "unit_inventory_sha256": self._environment.get(UNIT_INVENTORY_SHA256_ENV),
406
+ "response_protocol": RESPONSE_PROTOCOL,
407
+ }
408
+
409
+ def _manifest_pass_environment(
410
+ self,
411
+ manifest: ExperimentManifest,
412
+ ) -> tuple[str, ...]:
413
+ declared = {item.name for item in manifest.prerequisites}
414
+ names = [name for name in _BASE_PASSTHROUGH_ENVIRONMENTS if name in declared]
415
+ if "AILAB_BENCHMARK_CHECKOUT" in declared:
416
+ names.append("AILAB_BENCHMARK_CHECKOUT")
417
+ return tuple(dict.fromkeys(names))
418
+
419
+ def _request(
420
+ self,
421
+ manifest: ExperimentManifest,
422
+ cell: ExperimentCell,
423
+ arm_id: str,
424
+ ) -> Mapping[str, Any]:
425
+ arm = next(item for item in manifest.arms if item.arm_id == arm_id)
426
+ target = next(
427
+ item
428
+ for item in manifest.benchmarks
429
+ if item.cell_id == cell.benchmark_id and item.split == cell.split
430
+ )
431
+ payload = {
432
+ "schema_version": 1,
433
+ "protocol": REQUEST_PROTOCOL,
434
+ "manifest_hash": manifest.manifest_hash,
435
+ "cell": {
436
+ "cell_id": cell.cell_id,
437
+ "study_id": cell.study_id,
438
+ "benchmark_id": cell.benchmark_id,
439
+ "split": cell.split,
440
+ "unit_id": cell.unit_id,
441
+ "model_slot": cell.model_slot,
442
+ "seed": cell.seed,
443
+ },
444
+ "benchmark": {
445
+ "external": target.external,
446
+ "source_revision": target.source_revision,
447
+ },
448
+ "method": {
449
+ "method_id": self._configuration.method_id,
450
+ "candidate_release_id": self._configuration.candidate_release_id,
451
+ },
452
+ "arm": {
453
+ "arm_id": arm_id,
454
+ "release_id": arm.release_id,
455
+ "family": arm.family.value,
456
+ "profile_kind": arm.profile_kind.value,
457
+ "parameters": arm.parameters,
458
+ },
459
+ "parameters": {
460
+ "shared": self._configuration.shared_request_parameters,
461
+ "worker": self._configuration.workers[arm_id].request_parameters,
462
+ },
463
+ "asset_environments": list(self._manifest_pass_environment(manifest)),
464
+ }
465
+ require_secret_free(payload, label="method-process worker request")
466
+ return freeze_mapping(
467
+ {
468
+ **payload,
469
+ "request_hash": content_hash(payload),
470
+ }
471
+ )
472
+
473
+ def _require_preflight(
474
+ self,
475
+ manifest: ExperimentManifest,
476
+ cell: ExperimentCell,
477
+ ) -> None:
478
+ if self._manifest_hash != manifest.manifest_hash:
479
+ raise ArtifactError("method-process execution requires successful preflight")
480
+ if self._binding_receipt_hash is None:
481
+ raise ArtifactError("method-process binding receipt is unavailable")
482
+ if cell.manifest_hash != manifest.manifest_hash:
483
+ raise ValidationError("method-process cell belongs to another manifest")
484
+ if set(cell.arm_ids) != set(_ARM_IDS):
485
+ raise ValidationError("method-process cell requires no_op and candidate")
486
+ if cell.unit_id not in self._unit_ids:
487
+ raise ArtifactError("method-process cell is outside the preflighted unit inventory")
488
+
489
+
490
+ def factory() -> MethodProcessExperimentDriver:
491
+ path = os.environ.get(CONFIG_PATH_ENV)
492
+ expected = os.environ.get(CONFIG_SHA256_ENV)
493
+ if not path:
494
+ raise ArtifactError(f"{CONFIG_PATH_ENV} is required")
495
+ if not expected:
496
+ raise ArtifactError(f"{CONFIG_SHA256_ENV} is required")
497
+ return MethodProcessExperimentDriver.from_config(
498
+ path,
499
+ expected_sha256=expected,
500
+ supervisor=worker_supervisor_from_environment(),
501
+ )
502
+
503
+
504
+ def _load_configuration(
505
+ path: Path,
506
+ *,
507
+ expected_sha256: str,
508
+ environment: Mapping[str, str],
509
+ ) -> _Configuration:
510
+ require_sha256(expected_sha256, label=CONFIG_SHA256_ENV)
511
+ unresolved = path.expanduser()
512
+ if unresolved.is_symlink():
513
+ raise ArtifactError("method-process config must not be a symlink")
514
+ source = unresolved.resolve()
515
+ if not source.is_file():
516
+ raise ArtifactError("method-process config is not an existing file")
517
+ actual_sha256 = _sha256_file(source)
518
+ if actual_sha256 != expected_sha256:
519
+ raise ArtifactError("method-process config checksum differs")
520
+ try:
521
+ raw = json.loads(source.read_text(encoding="utf-8"))
522
+ except (OSError, UnicodeError, json.JSONDecodeError) as exc:
523
+ raise ArtifactError("method-process config is not valid UTF-8 JSON") from exc
524
+ data = _strict_mapping(raw, _CONFIG_FIELDS, label="method-process config")
525
+ require_secret_free(data, label="method-process config")
526
+ if data["schema_version"] != 1 or data["protocol"] != DRIVER_PROTOCOL:
527
+ raise ValidationError("unsupported method-process config")
528
+ method_id = _text(data["method_id"], "method_id")
529
+ candidate_release_id = _text(
530
+ data["candidate_release_id"],
531
+ "candidate_release_id",
532
+ )
533
+ raw_workers = _strict_mapping(
534
+ data["workers"],
535
+ frozenset(_ARM_IDS),
536
+ label="method-process workers",
537
+ )
538
+ workers: dict[str, LockedProcessWorker] = {}
539
+ for arm_id in _ARM_IDS:
540
+ worker_data = _strict_mapping(
541
+ raw_workers[arm_id],
542
+ _WORKER_FIELDS,
543
+ label=f"method-process worker {arm_id}",
544
+ )
545
+ workers[arm_id] = load_locked_process_worker(
546
+ arm_id,
547
+ worker_data,
548
+ environment=environment,
549
+ checkout_environment=_CANDIDATE_CHECKOUT_ENV,
550
+ adapter_checkout_environment=_CANDIDATE_CHECKOUT_ENV,
551
+ )
552
+ limits = ResourceLimits(
553
+ **_strict_mapping(
554
+ data["resource_limits"],
555
+ _LIMIT_FIELDS,
556
+ label="method-process resource_limits",
557
+ )
558
+ )
559
+ raw_pipes = _strict_mapping(
560
+ data["pipe_limits"],
561
+ _PIPE_FIELDS,
562
+ label="method-process pipe_limits",
563
+ )
564
+ pipes = {
565
+ name: _positive_integer(raw_pipes[name], f"pipe_limits.{name}")
566
+ for name in sorted(_PIPE_FIELDS)
567
+ }
568
+ parameters = _mapping(
569
+ data["shared_request_parameters"],
570
+ label="shared_request_parameters",
571
+ )
572
+ return _Configuration(
573
+ method_id=method_id,
574
+ candidate_release_id=candidate_release_id,
575
+ workers=workers,
576
+ resource_limits=limits,
577
+ pipe_limits=freeze_mapping(pipes),
578
+ shared_request_parameters=parameters,
579
+ config_sha256=actual_sha256,
580
+ )
581
+
582
+
583
+ def _load_unit_inventory(environment: Mapping[str, str]) -> tuple[str, ...]:
584
+ raw_path = environment.get(UNIT_INVENTORY_ENV)
585
+ expected = environment.get(UNIT_INVENTORY_SHA256_ENV)
586
+ if not raw_path:
587
+ raise ArtifactError(f"{UNIT_INVENTORY_ENV} is required")
588
+ if not expected:
589
+ raise ArtifactError(f"{UNIT_INVENTORY_SHA256_ENV} is required")
590
+ require_sha256(expected, label=UNIT_INVENTORY_SHA256_ENV)
591
+ path = Path(raw_path).expanduser().resolve()
592
+ if not path.is_file() or _sha256_file(path) != expected:
593
+ raise ArtifactError("method discovery unit inventory is absent or changed")
594
+ try:
595
+ raw = json.loads(path.read_text(encoding="utf-8"))
596
+ except (OSError, UnicodeError, json.JSONDecodeError) as exc:
597
+ raise ArtifactError("method discovery unit inventory is not valid UTF-8 JSON") from exc
598
+ if (
599
+ isinstance(raw, (str, bytes))
600
+ or not isinstance(raw, Sequence)
601
+ or not raw
602
+ or any(not isinstance(item, str) or not item.strip() for item in raw)
603
+ or len(raw) != len(set(raw))
604
+ ):
605
+ raise ValidationError(
606
+ "method discovery unit inventory must be a non-empty unique string array"
607
+ )
608
+ return tuple(raw)
609
+
610
+
611
+ def _strict_mapping(
612
+ value: Any,
613
+ fields: frozenset[str],
614
+ *,
615
+ label: str,
616
+ ) -> dict[str, Any]:
617
+ if not isinstance(value, Mapping) or set(value) != set(fields):
618
+ raise ValidationError(f"{label} fields are invalid")
619
+ return dict(value)
620
+
621
+
622
+ def _mapping(value: Any, *, label: str) -> Mapping[str, Any]:
623
+ if not isinstance(value, Mapping):
624
+ raise ValidationError(f"{label} must be an object")
625
+ try:
626
+ result = freeze_mapping(value)
627
+ except (TypeError, ValueError) as exc:
628
+ raise ValidationError(f"{label} must be canonical JSON") from exc
629
+ require_secret_free(result, label=f"method-process {label}")
630
+ return result
631
+
632
+
633
+ def _text(value: Any, label: str) -> str:
634
+ if not isinstance(value, str) or not value.strip():
635
+ raise ValidationError(f"{label} must be a non-empty string")
636
+ return value
637
+
638
+
639
+ def _positive_integer(value: Any, label: str) -> int:
640
+ if isinstance(value, bool) or not isinstance(value, int) or value < 1:
641
+ raise ValidationError(f"{label} must be a positive integer")
642
+ return value
643
+
644
+
645
+ def _sha256_file(path: Path) -> str:
646
+ digest = hashlib.sha256()
647
+ with path.open("rb") as handle:
648
+ for block in iter(lambda: handle.read(1024 * 1024), b""):
649
+ digest.update(block)
650
+ return digest.hexdigest()
651
+
652
+
653
+ __all__ = [
654
+ "CONFIG_PATH_ENV",
655
+ "CONFIG_SHA256_ENV",
656
+ "DRIVER_PROTOCOL",
657
+ "REQUEST_PROTOCOL",
658
+ "UNIT_INVENTORY_ENV",
659
+ "UNIT_INVENTORY_SHA256_ENV",
660
+ "MethodProcessExperimentDriver",
661
+ "factory",
662
+ ]