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,853 @@
1
+ """Explicit selector fit, calibration, and freeze producers.
2
+
3
+ The functions here consume a previously frozen :class:`SelectorDiscoveryFreeze`.
4
+ They never execute benchmark cells or fetch external assets. Every transition
5
+ returns an immutable selector bundle whose store enforces the lifecycle.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import math
12
+ import re
13
+ from collections.abc import Mapping, Sequence
14
+ from dataclasses import dataclass, replace
15
+ from pathlib import Path
16
+ from statistics import fmean
17
+ from typing import Any
18
+
19
+ from agentinputlab.contracts.enums import SemanticFamily
20
+ from agentinputlab.contracts.errors import ArtifactError, ValidationError
21
+ from agentinputlab.contracts.serialization import content_hash, freeze_mapping
22
+
23
+ from .advanced import (
24
+ CostRiskAwareSelector,
25
+ GBDTTLearnerSelector,
26
+ KNNUtilitySelector,
27
+ LogisticTLearnerSelector,
28
+ RidgeTLearnerSelector,
29
+ SelectorCalibrationResult,
30
+ calibrate_cost_risk_guardrails,
31
+ calibrate_selector_abstention,
32
+ fit_cost_risk_selector,
33
+ fit_gbdt_t_learner,
34
+ fit_knn_selector,
35
+ fit_logistic_t_learner,
36
+ fit_ridge_t_learner,
37
+ )
38
+ from .artifacts import SelectorArtifactBundle, SelectorArtifactStage
39
+ from .base import Selector, UtilityGainProvider
40
+ from .discovery import SelectorDiscoveryFreeze
41
+ from .learned import (
42
+ PolicyEvaluation,
43
+ RidgeUtilitySelector,
44
+ SelectorExample,
45
+ evaluate_selector,
46
+ fit_ridge_selector,
47
+ )
48
+ from .rules import RuleSelector
49
+
50
+ _SELECTOR_KINDS = frozenset(
51
+ {
52
+ "rule",
53
+ "ridge_utility",
54
+ "ridge_t_learner",
55
+ "logistic_t_learner",
56
+ "gbdt_t_learner",
57
+ "knn_utility",
58
+ "cost_risk_guardrail",
59
+ }
60
+ )
61
+ _PRIVACY_SAFE_GROUP_ID = re.compile(r"^group_[0-9a-f]{64}$")
62
+
63
+
64
+ @dataclass(frozen=True, slots=True)
65
+ class SelectorCalibrationSummary:
66
+ selector: Selector
67
+ evaluation: PolicyEvaluation
68
+ candidates_considered: int
69
+ receipt: Mapping[str, Any]
70
+
71
+ def __post_init__(self) -> None:
72
+ if not isinstance(self.selector, Selector):
73
+ raise ValidationError("calibration summary requires a Selector")
74
+ if not isinstance(self.evaluation, PolicyEvaluation):
75
+ raise ValidationError("calibration summary requires PolicyEvaluation")
76
+ if (
77
+ isinstance(self.candidates_considered, bool)
78
+ or not isinstance(self.candidates_considered, int)
79
+ or self.candidates_considered < 1
80
+ ):
81
+ raise ValidationError("calibration candidates_considered must be positive")
82
+ object.__setattr__(self, "receipt", freeze_mapping(self.receipt))
83
+
84
+
85
+ def fit_selector(
86
+ discovery: SelectorDiscoveryFreeze,
87
+ *,
88
+ selector_kind: str,
89
+ fit_config: Mapping[str, Any],
90
+ base_selector_bundle: SelectorArtifactBundle | None = None,
91
+ ) -> Selector:
92
+ """Fit one of the seven catalogued selectors from ``split='train'`` rows."""
93
+
94
+ if not isinstance(discovery, SelectorDiscoveryFreeze):
95
+ raise TypeError("selector fitting requires SelectorDiscoveryFreeze")
96
+ if selector_kind not in _SELECTOR_KINDS:
97
+ raise ValidationError(f"unsupported selector_kind: {selector_kind!r}")
98
+ if selector_kind != "cost_risk_guardrail" and base_selector_bundle is not None:
99
+ raise ValidationError("base_selector_bundle is valid only for cost_risk_guardrail")
100
+ config = _mapping(fit_config, label="fit config")
101
+ train = _examples_for_split(discovery, "train")
102
+ releases = discovery.representative_by_family
103
+
104
+ if selector_kind == "rule":
105
+ _require_exact_keys(config, {"threshold", "margin"}, label="rule fit config")
106
+ return RuleSelector(
107
+ threshold=_number(config["threshold"], label="threshold"),
108
+ margin=_number(config["margin"], label="margin"),
109
+ )
110
+ if selector_kind == "ridge_utility":
111
+ _require_exact_keys(config, {"ridge"}, label="ridge utility fit config")
112
+ return fit_ridge_selector(
113
+ train,
114
+ release_by_family=releases,
115
+ ridge=_nonnegative(config["ridge"], label="ridge"),
116
+ )
117
+ if selector_kind == "ridge_t_learner":
118
+ _require_exact_keys(config, {"ridge"}, label="ridge T-learner fit config")
119
+ return fit_ridge_t_learner(
120
+ train,
121
+ release_by_family=releases,
122
+ ridge=_nonnegative(config["ridge"], label="ridge"),
123
+ )
124
+ if selector_kind == "logistic_t_learner":
125
+ _require_exact_keys(
126
+ config,
127
+ {"l2", "learning_rate", "iterations"},
128
+ label="logistic T-learner fit config",
129
+ )
130
+ return fit_logistic_t_learner(
131
+ train,
132
+ release_by_family=releases,
133
+ l2=_nonnegative(config["l2"], label="l2"),
134
+ learning_rate=_positive(
135
+ config["learning_rate"],
136
+ label="learning_rate",
137
+ ),
138
+ iterations=_positive_integer(
139
+ config["iterations"],
140
+ label="iterations",
141
+ ),
142
+ )
143
+ if selector_kind == "gbdt_t_learner":
144
+ _require_exact_keys(
145
+ config,
146
+ {
147
+ "n_estimators",
148
+ "learning_rate",
149
+ "max_depth",
150
+ "min_samples_leaf",
151
+ "random_state",
152
+ },
153
+ label="GBDT T-learner fit config",
154
+ )
155
+ return fit_gbdt_t_learner(
156
+ train,
157
+ release_by_family=releases,
158
+ n_estimators=_positive_integer(
159
+ config["n_estimators"],
160
+ label="n_estimators",
161
+ ),
162
+ learning_rate=_positive(
163
+ config["learning_rate"],
164
+ label="learning_rate",
165
+ ),
166
+ max_depth=_positive_integer(config["max_depth"], label="max_depth"),
167
+ min_samples_leaf=_positive_integer(
168
+ config["min_samples_leaf"],
169
+ label="min_samples_leaf",
170
+ ),
171
+ random_state=_integer(config["random_state"], label="random_state"),
172
+ )
173
+ if selector_kind == "knn_utility":
174
+ _require_exact_keys(
175
+ config,
176
+ {"k", "distance_power"},
177
+ label="KNN utility fit config",
178
+ )
179
+ return fit_knn_selector(
180
+ train,
181
+ release_by_family=releases,
182
+ k=_positive_integer(config["k"], label="k"),
183
+ distance_power=_positive(
184
+ config["distance_power"],
185
+ label="distance_power",
186
+ ),
187
+ )
188
+
189
+ _require_exact_keys(
190
+ config,
191
+ {"max_cost", "max_risk", "cost_weight", "risk_weight"},
192
+ label="cost/risk guardrail fit config",
193
+ )
194
+ base_selector = _guardrail_base_selector(
195
+ discovery,
196
+ base_selector_bundle,
197
+ )
198
+ declared_releases = getattr(base_selector, "release_by_family", None)
199
+ if not isinstance(declared_releases, Mapping) or dict(declared_releases) != dict(releases):
200
+ raise ValidationError(
201
+ "cost/risk base selector release mapping differs from discovery freeze"
202
+ )
203
+ return fit_cost_risk_selector(
204
+ base_selector,
205
+ train,
206
+ release_by_family=releases,
207
+ max_cost=_nonnegative(config["max_cost"], label="max_cost"),
208
+ max_risk=_bounded(config["max_risk"], label="max_risk"),
209
+ cost_weight=_nonnegative(config["cost_weight"], label="cost_weight"),
210
+ risk_weight=_nonnegative(config["risk_weight"], label="risk_weight"),
211
+ )
212
+
213
+
214
+ def create_fitted_selector_bundle(
215
+ discovery: SelectorDiscoveryFreeze,
216
+ *,
217
+ selector_kind: str,
218
+ revision: str,
219
+ fit_config: Mapping[str, Any],
220
+ base_selector_bundle: SelectorArtifactBundle | None = None,
221
+ ) -> SelectorArtifactBundle:
222
+ """Fit and bind a selector to one exact discovery freeze."""
223
+
224
+ selector = fit_selector(
225
+ discovery,
226
+ selector_kind=selector_kind,
227
+ fit_config=fit_config,
228
+ base_selector_bundle=base_selector_bundle,
229
+ )
230
+ fit_lineage: Mapping[str, Any] = _selector_fit_lineage(
231
+ discovery,
232
+ fit_config=fit_config,
233
+ )
234
+ if selector_kind == "cost_risk_guardrail":
235
+ if not isinstance(base_selector_bundle, SelectorArtifactBundle):
236
+ raise ValidationError("cost_risk_guardrail requires a SelectorArtifactBundle base")
237
+ fit_lineage = _guardrail_fit_lineage(
238
+ discovery,
239
+ base_selector_bundle,
240
+ fit_config=fit_config,
241
+ )
242
+ return SelectorArtifactBundle.create(
243
+ selector,
244
+ stage=SelectorArtifactStage.FITTED,
245
+ revision=revision,
246
+ extractor_id=discovery.extractor_id,
247
+ extractor_revision=discovery.extractor_revision,
248
+ extractor_hash=discovery.extractor_hash,
249
+ feature_schema_id=discovery.feature_schema_id,
250
+ feature_schema_hash=discovery.feature_schema_hash,
251
+ representative_by_family=discovery.representative_by_family,
252
+ training_table_sha256=discovery.training_table.table_hash,
253
+ split_provenance_hash=discovery.split_provenance_hash,
254
+ comparison_profile_hash=discovery.comparison_profile_hash,
255
+ fit_lineage=fit_lineage,
256
+ )
257
+
258
+
259
+ def calibrate_selector_bundle(
260
+ fitted: SelectorArtifactBundle,
261
+ discovery: SelectorDiscoveryFreeze,
262
+ *,
263
+ revision: str,
264
+ calibration_config: Mapping[str, Any],
265
+ ) -> tuple[SelectorArtifactBundle, SelectorCalibrationSummary]:
266
+ """Calibrate only predeclared policy gates on discovery calibration rows."""
267
+
268
+ if not isinstance(fitted, SelectorArtifactBundle):
269
+ raise TypeError("selector calibration requires SelectorArtifactBundle")
270
+ if fitted.stage is not SelectorArtifactStage.FITTED:
271
+ raise ValidationError("selector calibration requires a fitted bundle")
272
+ _validate_discovery_binding(fitted, discovery)
273
+ config = _mapping(calibration_config, label="calibration config")
274
+ calibration = _examples_for_split(discovery, "calibration")
275
+ selector = fitted.selector()
276
+
277
+ if isinstance(selector, RuleSelector):
278
+ _require_exact_keys(
279
+ config,
280
+ {"threshold_grid", "margin_grid", "max_harm_rate"},
281
+ label="rule calibration config",
282
+ )
283
+ result = _calibrate_rule(
284
+ selector,
285
+ calibration,
286
+ threshold_grid=_number_array(
287
+ config["threshold_grid"],
288
+ label="threshold_grid",
289
+ lower=0.0,
290
+ upper=1.0,
291
+ ),
292
+ margin_grid=_number_array(
293
+ config["margin_grid"],
294
+ label="margin_grid",
295
+ lower=0.0,
296
+ ),
297
+ max_harm_rate=_bounded(
298
+ config["max_harm_rate"],
299
+ label="max_harm_rate",
300
+ ),
301
+ )
302
+ elif isinstance(selector, CostRiskAwareSelector):
303
+ _require_exact_keys(
304
+ config,
305
+ {
306
+ "max_cost_grid",
307
+ "max_risk_grid",
308
+ "gain_grid",
309
+ "margin_grid",
310
+ "max_harm_rate",
311
+ },
312
+ label="cost/risk calibration config",
313
+ )
314
+ advanced = calibrate_cost_risk_guardrails(
315
+ selector,
316
+ calibration,
317
+ max_cost_grid=_number_array(
318
+ config["max_cost_grid"],
319
+ label="max_cost_grid",
320
+ lower=0.0,
321
+ ),
322
+ max_risk_grid=_number_array(
323
+ config["max_risk_grid"],
324
+ label="max_risk_grid",
325
+ lower=0.0,
326
+ upper=1.0,
327
+ ),
328
+ gain_grid=_number_array(config["gain_grid"], label="gain_grid"),
329
+ margin_grid=_number_array(
330
+ config["margin_grid"],
331
+ label="margin_grid",
332
+ lower=0.0,
333
+ ),
334
+ max_harm_rate=_bounded(
335
+ config["max_harm_rate"],
336
+ label="max_harm_rate",
337
+ ),
338
+ )
339
+ result = _from_advanced_calibration(advanced)
340
+ elif isinstance(
341
+ selector,
342
+ (
343
+ RidgeUtilitySelector,
344
+ RidgeTLearnerSelector,
345
+ LogisticTLearnerSelector,
346
+ GBDTTLearnerSelector,
347
+ KNNUtilitySelector,
348
+ ),
349
+ ):
350
+ _require_exact_keys(
351
+ config,
352
+ {"gain_grid", "margin_grid", "max_harm_rate"},
353
+ label="selector calibration config",
354
+ )
355
+ advanced = calibrate_selector_abstention(
356
+ selector,
357
+ calibration,
358
+ gain_grid=_number_array(config["gain_grid"], label="gain_grid"),
359
+ margin_grid=_number_array(
360
+ config["margin_grid"],
361
+ label="margin_grid",
362
+ lower=0.0,
363
+ ),
364
+ max_harm_rate=_bounded(
365
+ config["max_harm_rate"],
366
+ label="max_harm_rate",
367
+ ),
368
+ )
369
+ result = _from_advanced_calibration(advanced)
370
+ else: # pragma: no cover - bundle codec admits exactly the seven selectors
371
+ raise ValidationError(f"unsupported selector calibration type: {type(selector).__name__}")
372
+
373
+ receipt = {
374
+ "schema_version": 1,
375
+ "predecessor_bundle_hash": fitted.bundle_hash,
376
+ "discovery_hash": discovery.discovery_hash,
377
+ "calibration_config_hash": content_hash(config),
378
+ "calibration_split_digest": discovery.training_table.group_split_digests["calibration"],
379
+ "candidates_considered": result.candidates_considered,
380
+ "evaluation": _evaluation_to_artifact(result.evaluation),
381
+ }
382
+ summary = SelectorCalibrationSummary(
383
+ selector=result.selector,
384
+ evaluation=result.evaluation,
385
+ candidates_considered=result.candidates_considered,
386
+ receipt=receipt,
387
+ )
388
+ calibrated = SelectorArtifactBundle.create(
389
+ result.selector,
390
+ stage=SelectorArtifactStage.CALIBRATED,
391
+ revision=revision,
392
+ extractor_id=fitted.extractor_id,
393
+ extractor_revision=fitted.extractor_revision,
394
+ extractor_hash=fitted.extractor_hash,
395
+ feature_schema_id=fitted.feature_schema_id,
396
+ feature_schema_hash=fitted.feature_schema_hash,
397
+ representative_by_family=fitted.representative_by_family,
398
+ training_table_sha256=fitted.training_table_sha256,
399
+ split_provenance_hash=fitted.split_provenance_hash,
400
+ comparison_profile_hash=fitted.comparison_profile_hash,
401
+ calibration_receipt=receipt,
402
+ fit_lineage=fitted.fit_lineage,
403
+ )
404
+ return calibrated, summary
405
+
406
+
407
+ def freeze_selector_bundle(
408
+ calibrated: SelectorArtifactBundle,
409
+ *,
410
+ revision: str,
411
+ ) -> SelectorArtifactBundle:
412
+ """Create a byte-equivalent policy at the terminal frozen stage."""
413
+
414
+ if not isinstance(calibrated, SelectorArtifactBundle):
415
+ raise TypeError("selector freeze requires SelectorArtifactBundle")
416
+ if calibrated.stage is not SelectorArtifactStage.CALIBRATED:
417
+ raise ValidationError("selector freeze requires a calibrated bundle")
418
+ return replace(
419
+ calibrated,
420
+ stage=SelectorArtifactStage.FROZEN,
421
+ revision=revision,
422
+ )
423
+
424
+
425
+ def build_selector_policy_manifest(
426
+ frozen: SelectorArtifactBundle,
427
+ discovery: SelectorDiscoveryFreeze,
428
+ ) -> Mapping[str, Any]:
429
+ """Derive the locked global comparator from the frozen calibration split.
430
+
431
+ The returned object is the exact schema consumed by the external-arena
432
+ driver. It is intentionally derived from a content-addressed discovery
433
+ freeze and a selector bundle already at the terminal ``frozen`` stage;
434
+ callers never type a family or release ID into the policy manifest by
435
+ hand.
436
+ """
437
+
438
+ if not isinstance(frozen, SelectorArtifactBundle):
439
+ raise TypeError("policy manifest production requires SelectorArtifactBundle")
440
+ if frozen.stage is not SelectorArtifactStage.FROZEN:
441
+ raise ValidationError("policy manifest requires a frozen selector bundle")
442
+ _validate_discovery_binding(frozen, discovery)
443
+ lineage = frozen.fit_lineage
444
+ lineage_discovery = lineage.get("discovery") if isinstance(lineage, Mapping) else None
445
+ if (
446
+ not isinstance(lineage_discovery, Mapping)
447
+ or lineage_discovery.get("revision") != discovery.revision
448
+ or lineage_discovery.get("sha256") != discovery.discovery_hash
449
+ ):
450
+ raise ValidationError(
451
+ "frozen selector fit lineage differs from the supplied discovery freeze"
452
+ )
453
+ calibration_receipt = frozen.calibration_receipt
454
+ if calibration_receipt.get(
455
+ "discovery_hash"
456
+ ) != discovery.discovery_hash or calibration_receipt.get(
457
+ "calibration_split_digest"
458
+ ) != discovery.training_table.group_split_digests.get("calibration"):
459
+ raise ValidationError(
460
+ "frozen selector calibration receipt differs from the supplied discovery freeze"
461
+ )
462
+
463
+ calibration = _examples_for_split(discovery, "calibration")
464
+ families = tuple(sorted(discovery.representative_by_family, key=lambda item: item.value))
465
+ if len(families) != 5 or any(
466
+ set(row.utilities) != {SemanticFamily.NO_OP, *families} for row in calibration
467
+ ):
468
+ raise ValidationError(
469
+ "locked best-eligible-global selection requires a full-five-family "
470
+ "calibration block for every state"
471
+ )
472
+ mean_utility = {
473
+ family: fmean(row.utilities[family] for row in calibration) for family in families
474
+ }
475
+ selected_family = min(
476
+ families,
477
+ key=lambda family: (-mean_utility[family], family.value),
478
+ )
479
+ selected_release = discovery.representative_by_family[selected_family]
480
+ calibration_digest = discovery.training_table.group_split_digests["calibration"]
481
+ members_by_split = {
482
+ split: tuple(
483
+ sorted({outcome.group_id for outcome in discovery.outcomes if outcome.split == split})
484
+ )
485
+ for split in ("train", "calibration")
486
+ }
487
+ if any(
488
+ not members or any(_PRIVACY_SAFE_GROUP_ID.fullmatch(item) is None for item in members)
489
+ for members in members_by_split.values()
490
+ ):
491
+ raise ValidationError(
492
+ "policy manifest requires privacy-safe benchmark-scoped group hashes "
493
+ "for train and calibration"
494
+ )
495
+ if set(members_by_split["train"]).intersection(members_by_split["calibration"]):
496
+ raise ValidationError("policy manifest group membership crosses splits")
497
+ partition_splits = {
498
+ split: {
499
+ "member_hashes": members,
500
+ "commitment_sha256": content_hash({"split": split, "group_ids": list(members)}),
501
+ }
502
+ for split, members in members_by_split.items()
503
+ }
504
+ if {split: row["commitment_sha256"] for split, row in partition_splits.items()} != {
505
+ split: discovery.training_table.group_split_digests[split]
506
+ for split in ("train", "calibration")
507
+ }:
508
+ raise ValidationError("policy group membership differs from the frozen split provenance")
509
+ return freeze_mapping(
510
+ {
511
+ "schema_version": 1,
512
+ "artifact": "agentinputlab.selector_policy_manifest",
513
+ "stage": "frozen",
514
+ "discovery": {
515
+ "revision": discovery.revision,
516
+ "sha256": discovery.discovery_hash,
517
+ },
518
+ "training_table_sha256": discovery.training_table.table_hash,
519
+ "split_provenance_hash": discovery.split_provenance_hash,
520
+ "comparison_profile_hash": discovery.comparison_profile_hash,
521
+ "representative_by_family": {
522
+ family.value: release_id
523
+ for family, release_id in sorted(
524
+ discovery.representative_by_family.items(),
525
+ key=lambda item: item[0].value,
526
+ )
527
+ },
528
+ "group_partition": {
529
+ "schema_version": 1,
530
+ "hash_scheme": "benchmark_group.content_hash.v1",
531
+ "splits": partition_splits,
532
+ },
533
+ "locked_best_eligible_global": {
534
+ "selected_family": selected_family.value,
535
+ "selected_release_id": selected_release,
536
+ "selection_receipt": {
537
+ "schema_version": 1,
538
+ "rule_id": "best_eligible_global.v1",
539
+ "selection_split": "calibration",
540
+ "training_table_sha256": discovery.training_table.table_hash,
541
+ "calibration_split_digest": calibration_digest,
542
+ },
543
+ },
544
+ }
545
+ )
546
+
547
+
548
+ def load_selector_fit_config(path: str | Path) -> tuple[str, Mapping[str, Any]]:
549
+ raw = _read_json(path, label="selector fit config")
550
+ _require_exact_keys(
551
+ raw,
552
+ {"schema_version", "selector_kind", "fit"},
553
+ label="selector fit config",
554
+ )
555
+ if _integer(raw["schema_version"], label="schema_version") != 1:
556
+ raise ValidationError("unsupported selector fit config schema")
557
+ kind = _text(raw["selector_kind"], label="selector_kind")
558
+ if kind not in _SELECTOR_KINDS:
559
+ raise ValidationError(f"unsupported selector_kind: {kind!r}")
560
+ return kind, freeze_mapping(_mapping(raw["fit"], label="fit"))
561
+
562
+
563
+ def load_selector_calibration_config(path: str | Path) -> Mapping[str, Any]:
564
+ raw = _read_json(path, label="selector calibration config")
565
+ _require_exact_keys(
566
+ raw,
567
+ {"schema_version", "calibration"},
568
+ label="selector calibration config",
569
+ )
570
+ if _integer(raw["schema_version"], label="schema_version") != 1:
571
+ raise ValidationError("unsupported selector calibration config schema")
572
+ return freeze_mapping(_mapping(raw["calibration"], label="calibration"))
573
+
574
+
575
+ def _guardrail_base_selector(
576
+ discovery: SelectorDiscoveryFreeze,
577
+ base_bundle: SelectorArtifactBundle | None,
578
+ ) -> UtilityGainProvider:
579
+ if not isinstance(base_bundle, SelectorArtifactBundle):
580
+ raise ValidationError(
581
+ "cost_risk_guardrail requires a SelectorArtifactBundle base, not a naked selector"
582
+ )
583
+ _validate_discovery_binding(base_bundle, discovery)
584
+ _validate_base_discovery_lineage(base_bundle, discovery)
585
+ base_selector = base_bundle.selector()
586
+ if not isinstance(base_selector, UtilityGainProvider):
587
+ raise ValidationError("cost_risk_guardrail base bundle must contain a UtilityGainProvider")
588
+ return base_selector
589
+
590
+
591
+ def _guardrail_fit_lineage(
592
+ discovery: SelectorDiscoveryFreeze,
593
+ base_bundle: SelectorArtifactBundle,
594
+ *,
595
+ fit_config: Mapping[str, Any],
596
+ ) -> Mapping[str, Any]:
597
+ _validate_discovery_binding(base_bundle, discovery)
598
+ return freeze_mapping(
599
+ {
600
+ "schema_version": 1,
601
+ "kind": "cost_risk_guardrail_base_bundle",
602
+ "discovery": {
603
+ "revision": discovery.revision,
604
+ "sha256": discovery.discovery_hash,
605
+ },
606
+ "fit_config_sha256": content_hash(_mapping(fit_config, label="fit config")),
607
+ "base_selector_bundle": {
608
+ "selector_id": base_bundle.selector_card_id,
609
+ "revision": base_bundle.revision,
610
+ "sha256": base_bundle.bundle_hash,
611
+ "stage": base_bundle.stage.value,
612
+ "model_hash": base_bundle.model_hash,
613
+ },
614
+ }
615
+ )
616
+
617
+
618
+ def _selector_fit_lineage(
619
+ discovery: SelectorDiscoveryFreeze,
620
+ *,
621
+ fit_config: Mapping[str, Any],
622
+ ) -> Mapping[str, Any]:
623
+ return freeze_mapping(
624
+ {
625
+ "schema_version": 1,
626
+ "kind": "selector_fit",
627
+ "discovery": {
628
+ "revision": discovery.revision,
629
+ "sha256": discovery.discovery_hash,
630
+ },
631
+ "fit_config_sha256": content_hash(_mapping(fit_config, label="fit config")),
632
+ }
633
+ )
634
+
635
+
636
+ def _validate_base_discovery_lineage(
637
+ base_bundle: SelectorArtifactBundle,
638
+ discovery: SelectorDiscoveryFreeze,
639
+ ) -> None:
640
+ lineage = base_bundle.fit_lineage
641
+ if not lineage:
642
+ raise ValidationError("cost_risk_guardrail base bundle lacks exact discovery fit lineage")
643
+ source = lineage.get("discovery")
644
+ if not isinstance(source, Mapping):
645
+ raise ValidationError("cost_risk_guardrail base bundle has invalid discovery fit lineage")
646
+ if (
647
+ source.get("revision") != discovery.revision
648
+ or source.get("sha256") != discovery.discovery_hash
649
+ ):
650
+ raise ValidationError(
651
+ "cost/risk base selector bundle was fitted from an unrelated SelectorDiscoveryFreeze"
652
+ )
653
+
654
+
655
+ def _validate_discovery_binding(
656
+ bundle: SelectorArtifactBundle,
657
+ discovery: SelectorDiscoveryFreeze,
658
+ ) -> None:
659
+ if not isinstance(discovery, SelectorDiscoveryFreeze):
660
+ raise TypeError("selector calibration requires SelectorDiscoveryFreeze")
661
+ expected = {
662
+ "extractor_id": discovery.extractor_id,
663
+ "extractor_revision": discovery.extractor_revision,
664
+ "extractor_hash": discovery.extractor_hash,
665
+ "feature_schema_id": discovery.feature_schema_id,
666
+ "feature_schema_hash": discovery.feature_schema_hash,
667
+ "representative_by_family": discovery.representative_by_family,
668
+ "training_table_sha256": discovery.training_table.table_hash,
669
+ "split_provenance_hash": discovery.split_provenance_hash,
670
+ "comparison_profile_hash": discovery.comparison_profile_hash,
671
+ }
672
+ if any(getattr(bundle, name) != value for name, value in expected.items()):
673
+ raise ValidationError("fitted selector bundle differs from the supplied discovery freeze")
674
+ if "calibration" not in discovery.training_table.group_split_digests:
675
+ raise ValidationError("discovery freeze contains no calibration split")
676
+
677
+
678
+ def _examples_for_split(
679
+ discovery: SelectorDiscoveryFreeze,
680
+ split: str,
681
+ ) -> tuple[SelectorExample, ...]:
682
+ rows = tuple(item for item in discovery.training_table.examples if item.split == split)
683
+ if not rows:
684
+ raise ValidationError(f"selector discovery freeze has no {split!r} examples")
685
+ return rows
686
+
687
+
688
+ def _calibrate_rule(
689
+ selector: RuleSelector,
690
+ examples: Sequence[SelectorExample],
691
+ *,
692
+ threshold_grid: Sequence[float],
693
+ margin_grid: Sequence[float],
694
+ max_harm_rate: float,
695
+ ) -> SelectorCalibrationResult:
696
+ candidates: list[tuple[PolicyEvaluation, RuleSelector]] = []
697
+ considered = 0
698
+ for threshold in threshold_grid:
699
+ for margin in margin_grid:
700
+ considered += 1
701
+ candidate = replace(
702
+ selector,
703
+ threshold=float(threshold),
704
+ margin=float(margin),
705
+ )
706
+ evaluation = evaluate_selector(
707
+ candidate,
708
+ examples,
709
+ required_split="calibration",
710
+ )
711
+ if evaluation.harm_rate <= max_harm_rate:
712
+ candidates.append((evaluation, candidate))
713
+ if not candidates:
714
+ raise ValidationError("no rule calibration candidate satisfies the harm constraint")
715
+ evaluation, selected = max(
716
+ candidates,
717
+ key=lambda item: (
718
+ item[0].mean_policy_value,
719
+ item[0].coverage,
720
+ -item[0].harm_rate,
721
+ -item[1].threshold,
722
+ -item[1].margin,
723
+ ),
724
+ )
725
+ return SelectorCalibrationResult(selected, evaluation, considered)
726
+
727
+
728
+ def _from_advanced_calibration(
729
+ result: SelectorCalibrationResult,
730
+ ) -> SelectorCalibrationResult:
731
+ if not isinstance(result, SelectorCalibrationResult): # pragma: no cover
732
+ raise TypeError("calibration API returned an invalid result")
733
+ return result
734
+
735
+
736
+ def _evaluation_to_artifact(value: PolicyEvaluation) -> dict[str, Any]:
737
+ return {
738
+ "count": value.count,
739
+ "coverage": value.coverage,
740
+ "mean_policy_value": value.mean_policy_value,
741
+ "mean_no_op_value": value.mean_no_op_value,
742
+ "mean_gain": value.mean_gain,
743
+ "harm_rate": value.harm_rate,
744
+ "oracle_regret": value.oracle_regret,
745
+ }
746
+
747
+
748
+ def _read_json(path: str | Path, *, label: str) -> dict[str, Any]:
749
+ source = Path(path).expanduser().resolve()
750
+ try:
751
+ raw = json.loads(source.read_text(encoding="utf-8"))
752
+ except (OSError, UnicodeError, json.JSONDecodeError) as exc:
753
+ raise ArtifactError(f"{label} is not valid UTF-8 JSON: {source}") from exc
754
+ return _mapping(raw, label=label)
755
+
756
+
757
+ def _require_exact_keys(
758
+ value: Mapping[str, Any],
759
+ expected: set[str],
760
+ *,
761
+ label: str,
762
+ ) -> None:
763
+ if set(value) != expected:
764
+ raise ValidationError(
765
+ f"{label} fields differ: expected {sorted(expected)!r}, got {sorted(value)!r}"
766
+ )
767
+
768
+
769
+ def _mapping(value: object, *, label: str) -> dict[str, Any]:
770
+ if not isinstance(value, Mapping) or any(not isinstance(key, str) for key in value):
771
+ raise ValidationError(f"{label} must be an object with string keys")
772
+ return dict(value)
773
+
774
+
775
+ def _array(value: object, *, label: str) -> list[Any]:
776
+ if not isinstance(value, (list, tuple)):
777
+ raise ValidationError(f"{label} must be an array")
778
+ return list(value)
779
+
780
+
781
+ def _text(value: object, *, label: str) -> str:
782
+ if not isinstance(value, str) or not value.strip() or value != value.strip():
783
+ raise ValidationError(f"{label} must be a trimmed non-empty string")
784
+ return value
785
+
786
+
787
+ def _integer(value: object, *, label: str) -> int:
788
+ if isinstance(value, bool) or not isinstance(value, int):
789
+ raise ValidationError(f"{label} must be an integer")
790
+ return value
791
+
792
+
793
+ def _positive_integer(value: object, *, label: str) -> int:
794
+ result = _integer(value, label=label)
795
+ if result < 1:
796
+ raise ValidationError(f"{label} must be positive")
797
+ return result
798
+
799
+
800
+ def _number(value: object, *, label: str) -> float:
801
+ if isinstance(value, bool) or not isinstance(value, (int, float)) or not math.isfinite(value):
802
+ raise ValidationError(f"{label} must be a finite number")
803
+ return float(value)
804
+
805
+
806
+ def _positive(value: object, *, label: str) -> float:
807
+ result = _number(value, label=label)
808
+ if result <= 0:
809
+ raise ValidationError(f"{label} must be positive")
810
+ return result
811
+
812
+
813
+ def _nonnegative(value: object, *, label: str) -> float:
814
+ result = _number(value, label=label)
815
+ if result < 0:
816
+ raise ValidationError(f"{label} must be non-negative")
817
+ return result
818
+
819
+
820
+ def _bounded(value: object, *, label: str) -> float:
821
+ result = _number(value, label=label)
822
+ if not 0 <= result <= 1:
823
+ raise ValidationError(f"{label} must be in [0, 1]")
824
+ return result
825
+
826
+
827
+ def _number_array(
828
+ value: object,
829
+ *,
830
+ label: str,
831
+ lower: float | None = None,
832
+ upper: float | None = None,
833
+ ) -> tuple[float, ...]:
834
+ raw = _array(value, label=label)
835
+ if not raw:
836
+ raise ValidationError(f"{label} must not be empty")
837
+ numbers = tuple(_number(item, label=f"{label} item") for item in raw)
838
+ if lower is not None and any(item < lower for item in numbers):
839
+ raise ValidationError(f"{label} values must be at least {lower:g}")
840
+ if upper is not None and any(item > upper for item in numbers):
841
+ raise ValidationError(f"{label} values must be at most {upper:g}")
842
+ return tuple(sorted(set(numbers)))
843
+
844
+
845
+ __all__ = [
846
+ "SelectorCalibrationSummary",
847
+ "calibrate_selector_bundle",
848
+ "create_fitted_selector_bundle",
849
+ "fit_selector",
850
+ "freeze_selector_bundle",
851
+ "load_selector_calibration_config",
852
+ "load_selector_fit_config",
853
+ ]