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,109 @@
1
+ """Transparent selector baseline used before learned selector confirmation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ from collections.abc import Collection
7
+ from dataclasses import dataclass
8
+
9
+ from agentinputlab.contracts.enums import SemanticFamily
10
+ from agentinputlab.contracts.serialization import content_hash
11
+ from agentinputlab.contracts.state import FrozenAgentState
12
+
13
+ from .base import SelectionDecision, SelectionFeatures
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class RuleSelector:
18
+ threshold: float = 0.6
19
+ margin: float = 0.1
20
+
21
+ def __post_init__(self) -> None:
22
+ if (
23
+ isinstance(self.threshold, bool)
24
+ or not isinstance(self.threshold, (int, float))
25
+ or not math.isfinite(self.threshold)
26
+ or not 0 <= self.threshold <= 1
27
+ ):
28
+ raise ValueError("rule selector threshold must be finite and in [0, 1]")
29
+ if (
30
+ isinstance(self.margin, bool)
31
+ or not isinstance(self.margin, (int, float))
32
+ or not math.isfinite(self.margin)
33
+ or self.margin < 0
34
+ ):
35
+ raise ValueError("rule selector margin must be finite and non-negative")
36
+
37
+ @property
38
+ def model_hash(self) -> str:
39
+ return content_hash(
40
+ {
41
+ "selector": "rule",
42
+ "threshold": self.threshold,
43
+ "margin": self.margin,
44
+ }
45
+ )
46
+
47
+ def select(
48
+ self,
49
+ state: FrozenAgentState,
50
+ features: SelectionFeatures,
51
+ *,
52
+ eligible_families: Collection[SemanticFamily] | None = None,
53
+ ) -> SelectionDecision:
54
+ del state
55
+ scores = {
56
+ SemanticFamily.CLARIFY.value: features.ambiguity_score,
57
+ SemanticFamily.DECOMPOSE.value: features.multi_step_score,
58
+ SemanticFamily.ACQUIRE.value: features.retrieval_need_score,
59
+ SemanticFamily.CURATE.value: features.context_pressure,
60
+ SemanticFamily.REFORMULATE.value: features.reformulation_need_score,
61
+ }
62
+ eligible = _eligible_actions(eligible_families)
63
+ ordered = sorted(
64
+ ((family.value, scores[family.value]) for family in eligible),
65
+ key=lambda item: (-item[1], item[0]),
66
+ )
67
+ if not ordered:
68
+ return SelectionDecision(
69
+ family=SemanticFamily.NO_OP,
70
+ release_id="baseline.no_op",
71
+ selection_score=0.0,
72
+ rationale="abstained: no intervention family is eligible",
73
+ scores=scores,
74
+ )
75
+ best_name, best_score = ordered[0]
76
+ runner_up = max(0.0, ordered[1][1] if len(ordered) > 1 else 0.0)
77
+ if best_score < self.threshold or best_score - runner_up <= self.margin:
78
+ return SelectionDecision(
79
+ family=SemanticFamily.NO_OP,
80
+ release_id="baseline.no_op",
81
+ selection_score=0.0,
82
+ rationale="abstained: no family passed threshold and margin",
83
+ scores=scores,
84
+ )
85
+ return SelectionDecision(
86
+ family=SemanticFamily(best_name),
87
+ release_id=None,
88
+ selection_score=best_score,
89
+ rationale=f"selected highest eligible family score: {best_name}",
90
+ scores=scores,
91
+ )
92
+
93
+
94
+ def _eligible_actions(
95
+ eligible_families: Collection[SemanticFamily] | None,
96
+ ) -> tuple[SemanticFamily, ...]:
97
+ actions = (
98
+ SemanticFamily.REFORMULATE,
99
+ SemanticFamily.DECOMPOSE,
100
+ SemanticFamily.ACQUIRE,
101
+ SemanticFamily.CLARIFY,
102
+ SemanticFamily.CURATE,
103
+ )
104
+ if eligible_families is None:
105
+ return actions
106
+ eligible = tuple(eligible_families)
107
+ if any(not isinstance(family, SemanticFamily) for family in eligible):
108
+ raise ValueError("eligible_families must contain SemanticFamily values")
109
+ return tuple(family for family in actions if family in eligible)
@@ -0,0 +1,420 @@
1
+ """Leakage-aware selector-to-intervention orchestration.
2
+
3
+ This module deliberately keeps feature extraction, release selection, and
4
+ intervention construction as separate auditable boundaries. A selector score
5
+ is not executable until the chosen release is validated against the canonical
6
+ registry and constructed by an explicitly locked factory.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import re
12
+ from collections.abc import Callable, Collection, Mapping
13
+ from dataclasses import dataclass, field
14
+ from types import MappingProxyType
15
+ from typing import TYPE_CHECKING, Protocol, runtime_checkable
16
+
17
+ from agentinputlab.contracts.enums import SemanticFamily, StrEnum, SupportStatus
18
+ from agentinputlab.contracts.errors import RegistryError, ValidationError
19
+ from agentinputlab.contracts.lifecycle import Intervention, InterventionContext
20
+ from agentinputlab.contracts.serialization import content_hash, freeze_mapping
21
+ from agentinputlab.contracts.state import FrozenAgentState
22
+ from agentinputlab.registry import AlgorithmRegistry
23
+ from agentinputlab.runner import InterventionRunner, RunRecord
24
+
25
+ from .base import SelectionDecision, SelectionFeatures, Selector
26
+ from .no_op import NoOpIntervention
27
+
28
+ if TYPE_CHECKING:
29
+ from .artifacts import SelectorArtifactBundle
30
+
31
+ _SHA256 = re.compile(r"^[0-9a-f]{64}$")
32
+ _DEFAULT_RUNNABLE_STATUSES = frozenset(
33
+ {
34
+ SupportStatus.EXPERIMENTAL,
35
+ SupportStatus.SUPPORTED,
36
+ }
37
+ )
38
+ _SELECTOR_ACTIONS = frozenset(
39
+ {
40
+ SemanticFamily.REFORMULATE,
41
+ SemanticFamily.DECOMPOSE,
42
+ SemanticFamily.ACQUIRE,
43
+ SemanticFamily.CLARIFY,
44
+ SemanticFamily.CURATE,
45
+ }
46
+ )
47
+
48
+
49
+ class FeatureAccessDomain(StrEnum):
50
+ """Domains a feature extractor may attest that it consulted."""
51
+
52
+ VISIBLE_PRE_ACTION = "visible_pre_action"
53
+ EVALUATOR_GOLD = "evaluator_gold"
54
+ POST_ACTION = "post_action"
55
+ OTHER_ARM_OUTCOME = "other_arm_outcome"
56
+
57
+
58
+ @dataclass(frozen=True, slots=True)
59
+ class FeatureObservation:
60
+ """One feature vector bound to a visible pre-action state and extractor."""
61
+
62
+ features: SelectionFeatures
63
+ state_hash: str
64
+ extractor_id: str
65
+ extractor_revision: str
66
+ access_domains: tuple[FeatureAccessDomain, ...] = (FeatureAccessDomain.VISIBLE_PRE_ACTION,)
67
+ provenance: Mapping[str, object] = field(default_factory=dict)
68
+
69
+ def __post_init__(self) -> None:
70
+ if not isinstance(self.features, SelectionFeatures):
71
+ raise ValidationError("feature observation requires SelectionFeatures")
72
+ for label, value in (
73
+ ("state_hash", self.state_hash),
74
+ ("extractor_id", self.extractor_id),
75
+ ("extractor_revision", self.extractor_revision),
76
+ ):
77
+ if not isinstance(value, str) or not value.strip():
78
+ raise ValidationError(f"feature observation {label} must be non-empty")
79
+ domains = tuple(self.access_domains)
80
+ if not domains or any(not isinstance(item, FeatureAccessDomain) for item in domains):
81
+ raise ValidationError("feature access domains must be typed and non-empty")
82
+ if set(domains) != {FeatureAccessDomain.VISIBLE_PRE_ACTION}:
83
+ raise ValidationError(
84
+ "selector features may access visible_pre_action state only; "
85
+ "gold, post-action data, and other-arm outcomes are forbidden"
86
+ )
87
+ object.__setattr__(self, "access_domains", domains)
88
+ object.__setattr__(self, "provenance", freeze_mapping(self.provenance))
89
+
90
+ @property
91
+ def feature_hash(self) -> str:
92
+ return content_hash(self)
93
+
94
+
95
+ @runtime_checkable
96
+ class FeatureExtractor(Protocol):
97
+ """Extract features from the physically gold-free state supplied by the runner."""
98
+
99
+ def extract(self, state: FrozenAgentState) -> FeatureObservation: ...
100
+
101
+
102
+ @dataclass(frozen=True, slots=True)
103
+ class SelectorArtifactIdentity:
104
+ selector_id: str
105
+ revision: str
106
+ sha256: str
107
+
108
+ def __post_init__(self) -> None:
109
+ if not isinstance(self.selector_id, str) or not self.selector_id.strip():
110
+ raise ValidationError("selector_id must be non-empty")
111
+ if not isinstance(self.revision, str) or not self.revision.strip():
112
+ raise ValidationError("selector revision must be non-empty")
113
+ if not isinstance(self.sha256, str) or not _SHA256.fullmatch(self.sha256):
114
+ raise ValidationError("selector identity requires a lowercase SHA-256")
115
+
116
+ @classmethod
117
+ def from_selector(
118
+ cls,
119
+ selector: Selector,
120
+ *,
121
+ selector_id: str,
122
+ revision: str,
123
+ ) -> SelectorArtifactIdentity:
124
+ declared = getattr(selector, "model_hash", None)
125
+ if isinstance(declared, str) and _SHA256.fullmatch(declared):
126
+ digest = declared
127
+ else:
128
+ try:
129
+ digest = content_hash(selector)
130
+ except TypeError as exc:
131
+ raise ValidationError(
132
+ "selector is not canonically hashable; provide a frozen selector artifact"
133
+ ) from exc
134
+ return cls(selector_id=selector_id, revision=revision, sha256=digest)
135
+
136
+
137
+ @runtime_checkable
138
+ class InterventionFactory(Protocol):
139
+ def create(self, release_id: str) -> Intervention: ...
140
+
141
+
142
+ @dataclass(frozen=True, slots=True)
143
+ class RegistryInterventionFactory:
144
+ """Construct only explicitly registered and locally approved releases."""
145
+
146
+ builders: Mapping[str, Callable[[], Intervention]]
147
+ registry: AlgorithmRegistry = field(default_factory=AlgorithmRegistry.default)
148
+ allowed_statuses: frozenset[SupportStatus] = _DEFAULT_RUNNABLE_STATUSES
149
+
150
+ def __post_init__(self) -> None:
151
+ builders = dict(self.builders)
152
+ if not builders:
153
+ raise ValidationError("intervention factory requires at least one builder")
154
+ statuses = frozenset(self.allowed_statuses)
155
+ if not statuses or any(not isinstance(item, SupportStatus) for item in statuses):
156
+ raise ValidationError("allowed_statuses must contain SupportStatus values")
157
+ for release_id, builder in builders.items():
158
+ if not isinstance(release_id, str) or not release_id.strip() or not callable(builder):
159
+ raise ValidationError("factory builders require release IDs and callables")
160
+ self.registry.get_release(release_id)
161
+ object.__setattr__(self, "builders", MappingProxyType(builders))
162
+ object.__setattr__(self, "allowed_statuses", statuses)
163
+
164
+ def create(self, release_id: str) -> Intervention:
165
+ method, release = self.registry.get_release(release_id)
166
+ if release.status not in self.allowed_statuses:
167
+ raise RegistryError(
168
+ f"selector release {release_id} has status {release.status.value}, "
169
+ "which is not enabled by this factory"
170
+ )
171
+ try:
172
+ intervention = self.builders[release_id]()
173
+ except KeyError as exc:
174
+ raise RegistryError(f"selector release {release_id} has no locked builder") from exc
175
+ if not isinstance(intervention, Intervention):
176
+ raise ValidationError("release builder did not return an Intervention")
177
+ if intervention.release_id != release_id:
178
+ raise ValidationError("release builder returned a different release identity")
179
+ if intervention.method_id != method.method_id:
180
+ raise ValidationError("release builder returned a different method identity")
181
+ if intervention.family is not method.semantic_family:
182
+ raise ValidationError("release builder returned a different semantic family")
183
+ return intervention
184
+
185
+
186
+ @dataclass(frozen=True, slots=True)
187
+ class SelectorRunRecord:
188
+ input_state_hash: str
189
+ feature_hash: str
190
+ selector_identity: SelectorArtifactIdentity
191
+ decision: SelectionDecision
192
+ executed_release_id: str
193
+ run: RunRecord
194
+ feature_observation: FeatureObservation | None = None
195
+
196
+ def __post_init__(self) -> None:
197
+ if self.input_state_hash != self.run.input_state_hash:
198
+ raise ValidationError("selector and intervention input state hashes differ")
199
+ if self.executed_release_id != self.run.release_id:
200
+ raise ValidationError("selector and intervention release IDs differ")
201
+ if self.feature_observation is not None:
202
+ if not isinstance(self.feature_observation, FeatureObservation):
203
+ raise ValidationError("selector run feature_observation has an invalid type")
204
+ if self.feature_observation.feature_hash != self.feature_hash:
205
+ raise ValidationError("selector run feature hash differs from its observation")
206
+ if self.feature_observation.state_hash != self.input_state_hash:
207
+ raise ValidationError("selector run observation is bound to another input state")
208
+
209
+
210
+ class SelectorRuntime:
211
+ """Extract, select, resolve, and execute one intervention or explicit NO_OP."""
212
+
213
+ def __init__(
214
+ self,
215
+ *,
216
+ selector: Selector,
217
+ selector_identity: SelectorArtifactIdentity,
218
+ feature_extractor: FeatureExtractor,
219
+ factory: InterventionFactory,
220
+ representative_by_family: Mapping[SemanticFamily, str] | None = None,
221
+ registry: AlgorithmRegistry | None = None,
222
+ runner: InterventionRunner | None = None,
223
+ selector_bundle: SelectorArtifactBundle | None = None,
224
+ ) -> None:
225
+ if not isinstance(selector, Selector):
226
+ raise ValidationError("selector does not satisfy the Selector protocol")
227
+ if not isinstance(feature_extractor, FeatureExtractor):
228
+ raise ValidationError("feature extractor does not satisfy its protocol")
229
+ if not isinstance(factory, InterventionFactory):
230
+ raise ValidationError("intervention factory does not satisfy its protocol")
231
+ if not isinstance(selector_identity, SelectorArtifactIdentity):
232
+ raise ValidationError("selector_identity must be SelectorArtifactIdentity")
233
+ from .artifacts import (
234
+ SelectorArtifactBundle,
235
+ SelectorArtifactStage,
236
+ selector_model_hash,
237
+ )
238
+
239
+ expected_identity = SelectorArtifactIdentity.from_selector(
240
+ selector,
241
+ selector_id=selector_identity.selector_id,
242
+ revision=selector_identity.revision,
243
+ )
244
+ extractor_id = getattr(feature_extractor, "extractor_id", None)
245
+ extractor_revision = getattr(feature_extractor, "extractor_revision", None)
246
+ extractor_hash = getattr(feature_extractor, "extractor_hash", None)
247
+ feature_schema_id = getattr(feature_extractor, "feature_schema_id", None)
248
+ feature_schema_hash = getattr(feature_extractor, "feature_schema_hash", None)
249
+ if selector_bundle is None:
250
+ if selector_identity.sha256 != expected_identity.sha256:
251
+ raise ValidationError("selector identity does not match the supplied model")
252
+ else:
253
+ if not isinstance(selector_bundle, SelectorArtifactBundle):
254
+ raise ValidationError("selector_bundle must be SelectorArtifactBundle")
255
+ if selector_bundle.stage is not SelectorArtifactStage.FROZEN:
256
+ raise ValidationError("SelectorRuntime requires a frozen selector bundle")
257
+ if (
258
+ selector_identity.selector_id != selector_bundle.selector_card_id
259
+ or selector_identity.revision != selector_bundle.revision
260
+ or selector_identity.sha256 != selector_bundle.bundle_hash
261
+ ):
262
+ raise ValidationError("selector identity does not match its frozen bundle")
263
+ if selector_model_hash(selector) != selector_bundle.model_hash:
264
+ raise ValidationError("selector model does not match its frozen bundle")
265
+ if (
266
+ extractor_id != selector_bundle.extractor_id
267
+ or extractor_revision != selector_bundle.extractor_revision
268
+ or extractor_hash != selector_bundle.extractor_hash
269
+ ):
270
+ raise ValidationError(
271
+ "feature extractor identity does not match the frozen selector bundle"
272
+ )
273
+ if (
274
+ feature_schema_id != selector_bundle.feature_schema_id
275
+ or feature_schema_hash != selector_bundle.feature_schema_hash
276
+ ):
277
+ raise ValidationError(
278
+ "feature schema identity does not match the frozen selector bundle"
279
+ )
280
+ representatives = dict(representative_by_family or {})
281
+ if any(
282
+ not isinstance(family, SemanticFamily)
283
+ or family in {SemanticFamily.NO_OP, SemanticFamily.COMPOSITE}
284
+ or not isinstance(release_id, str)
285
+ or not release_id.strip()
286
+ for family, release_id in representatives.items()
287
+ ):
288
+ raise ValidationError("representative mapping requires intervention families and IDs")
289
+ model_representatives = getattr(selector, "release_by_family", None)
290
+ if isinstance(model_representatives, Mapping):
291
+ declared = dict(model_representatives)
292
+ overlap = set(representatives) & set(declared)
293
+ if any(representatives[family] != declared[family] for family in overlap):
294
+ raise ValidationError(
295
+ "runtime representatives differ from selector release mapping"
296
+ )
297
+ representatives = {**declared, **representatives}
298
+ if selector_bundle is not None:
299
+ bundle_representatives = dict(selector_bundle.representative_by_family)
300
+ if representatives and representatives != bundle_representatives:
301
+ raise ValidationError(
302
+ "runtime representatives differ from the frozen selector bundle"
303
+ )
304
+ representatives = bundle_representatives
305
+ self.selector = selector
306
+ self.selector_identity = selector_identity
307
+ self.selector_bundle = selector_bundle
308
+ self.feature_extractor = feature_extractor
309
+ self.extractor_id = extractor_id
310
+ self.extractor_revision = extractor_revision
311
+ self.extractor_hash = extractor_hash
312
+ self.feature_schema_id = feature_schema_id
313
+ self.feature_schema_hash = feature_schema_hash
314
+ self.factory = factory
315
+ self.representative_by_family = MappingProxyType(representatives)
316
+ self.registry = registry or AlgorithmRegistry.default()
317
+ self.runner = runner or InterventionRunner()
318
+ for family, release_id in representatives.items():
319
+ method, _ = self.registry.get_release(release_id)
320
+ if method.semantic_family is not family:
321
+ raise ValidationError(
322
+ f"representative {release_id} does not belong to {family.value}"
323
+ )
324
+
325
+ def run(
326
+ self,
327
+ state: FrozenAgentState,
328
+ context: InterventionContext,
329
+ *,
330
+ eligible_families: Collection[SemanticFamily] | None = None,
331
+ ) -> SelectorRunRecord:
332
+ observation = self.feature_extractor.extract(state)
333
+ if not isinstance(observation, FeatureObservation):
334
+ raise ValidationError("feature extractor did not return FeatureObservation")
335
+ if observation.state_hash != state.state_hash:
336
+ raise ValidationError("feature observation is bound to another input state")
337
+ if (self.extractor_id is not None and observation.extractor_id != self.extractor_id) or (
338
+ self.extractor_revision is not None
339
+ and observation.extractor_revision != self.extractor_revision
340
+ ):
341
+ raise ValidationError(
342
+ "feature observation identity differs from the configured extractor"
343
+ )
344
+ if self.selector_bundle is not None:
345
+ expected_provenance = {
346
+ "extractor_hash": self.selector_bundle.extractor_hash,
347
+ "schema_id": self.selector_bundle.feature_schema_id,
348
+ "schema_hash": self.selector_bundle.feature_schema_hash,
349
+ }
350
+ if any(
351
+ observation.provenance.get(key) != value
352
+ for key, value in expected_provenance.items()
353
+ ):
354
+ raise ValidationError(
355
+ "feature observation provenance differs from the frozen selector bundle"
356
+ )
357
+ decision = self.selector.select(
358
+ state,
359
+ observation.features,
360
+ eligible_families=eligible_families,
361
+ )
362
+ if not isinstance(decision, SelectionDecision):
363
+ raise ValidationError("selector did not return SelectionDecision")
364
+ if decision.family not in {*_SELECTOR_ACTIONS, SemanticFamily.NO_OP}:
365
+ raise ValidationError(f"selector chose unsupported family {decision.family.value}")
366
+ if eligible_families is not None:
367
+ eligible = tuple(eligible_families)
368
+ if any(not isinstance(family, SemanticFamily) for family in eligible):
369
+ raise ValidationError("eligible_families must contain SemanticFamily values")
370
+ if decision.family is not SemanticFamily.NO_OP and decision.family not in eligible:
371
+ raise ValidationError(f"selector chose ineligible family {decision.family.value}")
372
+ if decision.family is SemanticFamily.NO_OP:
373
+ if decision.release_id not in {None, "baseline.no_op"}:
374
+ raise ValidationError("NO_OP selector decisions may reference baseline.no_op only")
375
+ intervention: Intervention = NoOpIntervention()
376
+ else:
377
+ locked_release = self.representative_by_family.get(decision.family)
378
+ if (
379
+ decision.release_id is not None
380
+ and locked_release is not None
381
+ and decision.release_id != locked_release
382
+ ):
383
+ raise RegistryError(
384
+ f"selector chose release {decision.release_id} instead of frozen "
385
+ f"representative {locked_release}"
386
+ )
387
+ release_id = decision.release_id or locked_release
388
+ if release_id is None:
389
+ raise RegistryError(
390
+ f"selector chose {decision.family.value} without a release or locked representative"
391
+ )
392
+ method, _ = self.registry.get_release(release_id)
393
+ if method.semantic_family is not decision.family:
394
+ raise RegistryError(
395
+ f"selector release {release_id} belongs to {method.semantic_family.value}, "
396
+ f"not {decision.family.value}"
397
+ )
398
+ intervention = self.factory.create(release_id)
399
+ run = self.runner.run(intervention, state, context)
400
+ return SelectorRunRecord(
401
+ input_state_hash=state.state_hash,
402
+ feature_hash=observation.feature_hash,
403
+ selector_identity=self.selector_identity,
404
+ decision=decision,
405
+ executed_release_id=intervention.release_id,
406
+ run=run,
407
+ feature_observation=observation,
408
+ )
409
+
410
+
411
+ __all__ = [
412
+ "FeatureAccessDomain",
413
+ "FeatureExtractor",
414
+ "FeatureObservation",
415
+ "InterventionFactory",
416
+ "RegistryInterventionFactory",
417
+ "SelectorArtifactIdentity",
418
+ "SelectorRunRecord",
419
+ "SelectorRuntime",
420
+ ]
@@ -0,0 +1,16 @@
1
+ """Smoke, discovery, confirmation, selector, and transfer study orchestration."""
2
+
3
+ from .design import StudyArmSpec, StudyCell, StudyPlan, build_study_plan
4
+ from .paired import ArmFailure, ArmOutcome, PairedArm, PairedRun, PairedStudyRunner
5
+
6
+ __all__ = [
7
+ "ArmFailure",
8
+ "ArmOutcome",
9
+ "PairedArm",
10
+ "PairedRun",
11
+ "PairedStudyRunner",
12
+ "StudyArmSpec",
13
+ "StudyCell",
14
+ "StudyPlan",
15
+ "build_study_plan",
16
+ ]