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,110 @@
1
+ """Packaged benchmark inventory."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from collections.abc import Mapping
7
+ from dataclasses import dataclass
8
+ from importlib import resources
9
+ from typing import Any
10
+
11
+ from agentinputlab.contracts.enums import SemanticFamily
12
+ from agentinputlab.contracts.errors import RegistryError
13
+
14
+ EXPECTED_BENCHMARK_CELL_COUNT = 31
15
+
16
+
17
+ @dataclass(frozen=True, slots=True)
18
+ class BenchmarkCell:
19
+ cell_id: str
20
+ suite: str
21
+ task: str
22
+ size: str
23
+ families: tuple[SemanticFamily, ...]
24
+ source_revision: str
25
+ metrics: tuple[str, ...]
26
+ eligibility_gate: str = ""
27
+ family_support: str = "cell_declared"
28
+ adapter_metrics: tuple[str, ...] = ()
29
+ paired_metrics: tuple[str, ...] = ()
30
+ study_metrics: tuple[str, ...] = ()
31
+
32
+ def __post_init__(self) -> None:
33
+ if self.family_support not in {"cell_declared", "checkpoint_conditional"}:
34
+ raise ValueError("benchmark family_support has an unsupported value")
35
+ if not self.metrics or len(self.metrics) != len(set(self.metrics)):
36
+ raise ValueError("benchmark metrics must be non-empty and unique")
37
+ adapter = tuple(self.adapter_metrics)
38
+ paired = tuple(self.paired_metrics)
39
+ study = tuple(self.study_metrics)
40
+ if not adapter and not paired and not study:
41
+ adapter = tuple(self.metrics)
42
+ layered = (*adapter, *paired, *study)
43
+ if len(layered) != len(set(layered)) or set(layered) != set(self.metrics):
44
+ raise ValueError("benchmark metric layers must partition metrics exactly")
45
+ object.__setattr__(self, "adapter_metrics", adapter)
46
+ object.__setattr__(self, "paired_metrics", paired)
47
+ object.__setattr__(self, "study_metrics", study)
48
+
49
+ @classmethod
50
+ def from_mapping(cls, value: Mapping[str, Any]) -> BenchmarkCell:
51
+ try:
52
+ return cls(
53
+ cell_id=str(value["cell_id"]),
54
+ suite=str(value["suite"]),
55
+ task=str(value["task"]),
56
+ size=str(value["size"]),
57
+ families=tuple(SemanticFamily(item) for item in value["families"]),
58
+ source_revision=str(value["source_revision"]),
59
+ metrics=tuple(str(item) for item in value["metrics"]),
60
+ eligibility_gate=str(value.get("eligibility_gate", "")),
61
+ family_support=str(value.get("family_support", "cell_declared")),
62
+ adapter_metrics=tuple(str(item) for item in value.get("adapter_metrics", ())),
63
+ paired_metrics=tuple(str(item) for item in value.get("paired_metrics", ())),
64
+ study_metrics=tuple(str(item) for item in value.get("study_metrics", ())),
65
+ )
66
+ except (KeyError, TypeError, ValueError) as exc:
67
+ raise RegistryError(f"invalid benchmark cell: {value!r}") from exc
68
+
69
+
70
+ class BenchmarkRegistry:
71
+ def __init__(self, cells: tuple[BenchmarkCell, ...]) -> None:
72
+ if len(cells) != EXPECTED_BENCHMARK_CELL_COUNT:
73
+ raise RegistryError(
74
+ "benchmark registry requires "
75
+ f"{EXPECTED_BENCHMARK_CELL_COUNT} cells, got {len(cells)}"
76
+ )
77
+ if len({cell.cell_id for cell in cells}) != len(cells):
78
+ raise RegistryError("benchmark cell IDs must be unique")
79
+ self._cells = cells
80
+ self._by_id = {cell.cell_id: cell for cell in cells}
81
+
82
+ @classmethod
83
+ def default(cls) -> BenchmarkRegistry:
84
+ resource = resources.files("agentinputlab.benchmarks").joinpath("data", "registry.json")
85
+ payload = json.loads(resource.read_text(encoding="utf-8"))
86
+ if (
87
+ payload.get("schema_version") != 1
88
+ or payload.get("cell_count") != EXPECTED_BENCHMARK_CELL_COUNT
89
+ ):
90
+ raise RegistryError("unsupported benchmark registry snapshot")
91
+ return cls(tuple(BenchmarkCell.from_mapping(item) for item in payload["cells"]))
92
+
93
+ def get(self, cell_id: str) -> BenchmarkCell:
94
+ try:
95
+ return self._by_id[cell_id]
96
+ except KeyError as exc:
97
+ raise RegistryError(f"unknown benchmark cell: {cell_id}") from exc
98
+
99
+ def list(
100
+ self,
101
+ *,
102
+ family: SemanticFamily | str | None = None,
103
+ ) -> tuple[BenchmarkCell, ...]:
104
+ selected = SemanticFamily(family) if isinstance(family, str) else family
105
+ if selected is None:
106
+ return self._cells
107
+ return tuple(cell for cell in self._cells if selected in cell.families)
108
+
109
+ def __len__(self) -> int:
110
+ return len(self._cells)
@@ -0,0 +1,459 @@
1
+ """Prepared retrieval benchmark adapter with evaluator-only qrels.
2
+
3
+ The adapter consumes the checksum-verified normalized representation produced
4
+ by :mod:`agentinputlab.benchmarks.preprocess`. Prediction callbacks see only
5
+ the query-side state; qrels remain attached to ``BenchmarkExample`` and cross
6
+ the boundary only inside :meth:`score`.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import math
13
+ from collections.abc import Mapping, Sequence
14
+ from dataclasses import dataclass
15
+ from pathlib import Path
16
+ from types import MappingProxyType
17
+ from typing import Any
18
+
19
+ from agentinputlab.contracts.errors import ArtifactError, ValidationError
20
+ from agentinputlab.contracts.serialization import canonical_json, freeze_mapping
21
+ from agentinputlab.metrics import retrieval_aggregates
22
+
23
+ from .base import BenchmarkExample
24
+ from .preprocess import PreparedBenchmark
25
+
26
+
27
+ @dataclass(frozen=True, slots=True)
28
+ class _NamedRetrievalProfile:
29
+ query_asset_id: str
30
+ query_processor: str
31
+ split: str
32
+ corpus_asset_id: str | None = None
33
+ corpus_processor: str | None = None
34
+
35
+
36
+ _NAMED_RETRIEVAL_PROFILES = {
37
+ "beir.arguana": _NamedRetrievalProfile(
38
+ query_asset_id="beir.arguana.official",
39
+ query_processor="beir_zip_v1",
40
+ split="test",
41
+ ),
42
+ "bright.earth_science": _NamedRetrievalProfile(
43
+ query_asset_id="bright.earth_science.examples",
44
+ query_processor="bright_examples_parquet_v1",
45
+ split="test",
46
+ corpus_asset_id="bright.earth_science.corpus",
47
+ corpus_processor="bright_corpus_parquet_v1",
48
+ ),
49
+ "bright.economics": _NamedRetrievalProfile(
50
+ query_asset_id="bright.economics.examples",
51
+ query_processor="bright_examples_parquet_v1",
52
+ split="test",
53
+ corpus_asset_id="bright.economics.corpus",
54
+ corpus_processor="bright_corpus_parquet_v1",
55
+ ),
56
+ }
57
+
58
+
59
+ @dataclass(frozen=True, slots=True)
60
+ class RetrievalPrediction:
61
+ """One ranked retrieval run represented by document scores."""
62
+
63
+ scores: Mapping[str, float]
64
+
65
+ def __post_init__(self) -> None:
66
+ converted: dict[str, float] = {}
67
+ for document_id, score in self.scores.items():
68
+ if not isinstance(document_id, str) or not document_id.strip():
69
+ raise ValidationError("retrieval document IDs must be non-empty strings")
70
+ if isinstance(score, bool) or not isinstance(score, (int, float)):
71
+ raise ValidationError("retrieval scores must be numeric")
72
+ numeric = float(score)
73
+ if not math.isfinite(numeric):
74
+ raise ValidationError("retrieval scores must be finite")
75
+ converted[document_id] = numeric
76
+ object.__setattr__(self, "scores", MappingProxyType(converted))
77
+
78
+ @classmethod
79
+ def from_ranked_ids(cls, document_ids: Sequence[str]) -> RetrievalPrediction:
80
+ if isinstance(document_ids, str):
81
+ raise ValidationError("ranked document IDs must be a sequence, not one string")
82
+ ids = tuple(document_ids)
83
+ if len(ids) != len(set(ids)):
84
+ raise ValidationError("ranked retrieval predictions must not contain duplicates")
85
+ size = len(ids)
86
+ return cls({document_id: float(size - rank) for rank, document_id in enumerate(ids)})
87
+
88
+
89
+ class PreparedRetrievalBenchmarkAdapter:
90
+ """Production adapter for a verified, normalized retrieval benchmark."""
91
+
92
+ pairing_mode = "stateless_score_twice"
93
+
94
+ def __init__(
95
+ self,
96
+ prepared: PreparedBenchmark,
97
+ *,
98
+ benchmark_id: str,
99
+ split: str = "test",
100
+ corpus_prepared: PreparedBenchmark | None = None,
101
+ ) -> None:
102
+ if not isinstance(prepared, PreparedBenchmark):
103
+ raise TypeError("prepared must be a PreparedBenchmark")
104
+ _validated_identity(benchmark_id, label="benchmark_id")
105
+ _validated_identity(split, label="split")
106
+ if corpus_prepared is not None and not isinstance(corpus_prepared, PreparedBenchmark):
107
+ raise TypeError("corpus_prepared must be a PreparedBenchmark")
108
+ named_profile = _NAMED_RETRIEVAL_PROFILES.get(benchmark_id)
109
+ if named_profile is None:
110
+ _validate_prepared_identity(
111
+ prepared,
112
+ benchmark_id=benchmark_id,
113
+ split=split,
114
+ label="prepared retrieval query/gold",
115
+ require_complete=prepared.processor == "bright_examples_parquet_v1",
116
+ )
117
+ if corpus_prepared is not None:
118
+ _validate_prepared_identity(
119
+ corpus_prepared,
120
+ benchmark_id=benchmark_id,
121
+ split=split,
122
+ label="prepared retrieval corpus",
123
+ require_complete=True,
124
+ )
125
+ else:
126
+ _validate_named_prepared_identity(
127
+ prepared,
128
+ benchmark_id=benchmark_id,
129
+ split=split,
130
+ expected_asset_id=named_profile.query_asset_id,
131
+ expected_processor=named_profile.query_processor,
132
+ expected_split=named_profile.split,
133
+ label="prepared retrieval query/gold",
134
+ )
135
+ if named_profile.corpus_asset_id is None:
136
+ if corpus_prepared is not None:
137
+ raise ArtifactError(
138
+ f"named retrieval profile {benchmark_id!r} does not accept "
139
+ "a separate corpus"
140
+ )
141
+ else:
142
+ if corpus_prepared is None:
143
+ raise ArtifactError(
144
+ f"named retrieval profile {benchmark_id!r} requires its locked corpus"
145
+ )
146
+ _validate_named_prepared_identity(
147
+ corpus_prepared,
148
+ benchmark_id=benchmark_id,
149
+ split=split,
150
+ expected_asset_id=named_profile.corpus_asset_id,
151
+ expected_processor=named_profile.corpus_processor,
152
+ expected_split=named_profile.split,
153
+ label="prepared retrieval corpus",
154
+ )
155
+
156
+ input_rows = _records_by_id(prepared.inputs_path, label="prepared retrieval inputs")
157
+ gold_rows = _records_by_id(prepared.gold_path, label="prepared retrieval gold")
158
+ if set(input_rows) != set(gold_rows):
159
+ raise ArtifactError("prepared retrieval input and gold IDs do not match")
160
+ effective_corpus = corpus_prepared or prepared
161
+ corpus_path = effective_corpus.corpus_path
162
+ if corpus_path is None:
163
+ raise ArtifactError("prepared retrieval benchmark requires a corpus")
164
+
165
+ examples: list[BenchmarkExample] = []
166
+ for example_id in sorted(input_rows):
167
+ visible = input_rows[example_id]
168
+ evaluator = gold_rows[example_id]
169
+ query = _required_text(visible, "query", label="prepared retrieval input")
170
+ instruction = _required_text(
171
+ visible,
172
+ "instruction",
173
+ label="prepared retrieval input",
174
+ )
175
+ metadata = _visible_metadata(
176
+ visible.get("visible_metadata", {}),
177
+ benchmark_id=benchmark_id,
178
+ split=split,
179
+ require_source_split=(
180
+ prepared.processor == "bright_examples_parquet_v1"
181
+ or (named_profile is not None and named_profile.corpus_asset_id is not None)
182
+ ),
183
+ )
184
+ relevance = evaluator.get("relevance")
185
+ if not isinstance(relevance, Mapping) or not relevance:
186
+ raise ArtifactError("prepared retrieval gold requires non-empty relevance labels")
187
+ normalized_relevance: dict[str, int] = {}
188
+ for document_id, value in relevance.items():
189
+ if not isinstance(document_id, str) or not document_id:
190
+ raise ArtifactError("prepared retrieval qrel IDs must be non-empty strings")
191
+ if isinstance(value, bool) or not isinstance(value, int) or value < 0:
192
+ raise ArtifactError("prepared retrieval qrels must be non-negative integers")
193
+ normalized_relevance[document_id] = value
194
+ if not any(value > 0 for value in normalized_relevance.values()):
195
+ raise ArtifactError("prepared retrieval example requires a positive qrel")
196
+
197
+ evaluator_metadata: Mapping[str, Any] | None = None
198
+ excluded_document_ids: tuple[str, ...] = ()
199
+ if "evaluator_metadata" in evaluator:
200
+ raw_evaluator_metadata = evaluator["evaluator_metadata"]
201
+ if not isinstance(raw_evaluator_metadata, Mapping):
202
+ raise ArtifactError("prepared retrieval evaluator_metadata must be an object")
203
+ excluded_document_ids = _excluded_document_ids(raw_evaluator_metadata)
204
+ if set(excluded_document_ids) & set(normalized_relevance):
205
+ raise ArtifactError(
206
+ "prepared retrieval excluded document IDs overlap relevance labels"
207
+ )
208
+ evaluator_metadata = _frozen_canonical_mapping(
209
+ raw_evaluator_metadata,
210
+ label="prepared retrieval evaluator_metadata",
211
+ )
212
+ evaluator_gold: dict[str, Any] = {"relevance": normalized_relevance}
213
+ if evaluator_metadata is not None:
214
+ evaluator_gold["evaluator_metadata"] = evaluator_metadata
215
+ examples.append(
216
+ BenchmarkExample(
217
+ example_id=example_id,
218
+ query=query,
219
+ instruction=instruction,
220
+ visible_metadata=metadata,
221
+ evaluator_gold=_frozen_canonical_mapping(
222
+ evaluator_gold,
223
+ label="prepared retrieval evaluator gold",
224
+ ),
225
+ )
226
+ )
227
+ self.benchmark_id = benchmark_id
228
+ self.split = split
229
+ self.prepared = prepared
230
+ self.query_prepared = prepared
231
+ self.corpus_prepared = effective_corpus
232
+ self.corpus_path = corpus_path
233
+ self._ignore_identical_ids = prepared.processor == "beir_zip_v1"
234
+ self._examples = tuple(examples)
235
+ self._examples_by_id = {example.example_id: example for example in examples}
236
+
237
+ def examples(self, split: str) -> tuple[BenchmarkExample, ...]:
238
+ if split != self.split:
239
+ raise ValidationError(
240
+ f"prepared retrieval adapter exposes split {self.split!r}, not {split!r}"
241
+ )
242
+ return self._examples
243
+
244
+ def example(self, split: str, example_id: str) -> BenchmarkExample:
245
+ """Resolve one verified unit without rescanning the full split."""
246
+
247
+ if split != self.split:
248
+ raise ValidationError(
249
+ f"prepared retrieval adapter exposes split {self.split!r}, not {split!r}"
250
+ )
251
+ if not isinstance(example_id, str) or not example_id.strip():
252
+ raise ValidationError("prepared retrieval example_id must be non-empty")
253
+ try:
254
+ return self._examples_by_id[example_id]
255
+ except KeyError as exc:
256
+ raise ValidationError(
257
+ f"prepared retrieval split does not contain example {example_id!r}"
258
+ ) from exc
259
+
260
+ def fingerprint(self) -> Mapping[str, Any]:
261
+ """Portable prepared-source identities without exposing qrel contents.
262
+
263
+ Hashes were verified while loading the immutable prepared cache. Do not
264
+ rescan a potentially large corpus each time a caller binds a runtime.
265
+ Evaluation dependencies are resolved only by ``score``, not this method.
266
+ """
267
+ def prepared(value: PreparedBenchmark) -> dict[str, Any]:
268
+ return dict(
269
+ asset_id=value.asset_id,
270
+ processor=value.processor,
271
+ processor_revision=value.processor_revision,
272
+ source_sha256=value.source_sha256,
273
+ source_revision=value.source_revision,
274
+ cell_id=value.cell_id,
275
+ split=value.split,
276
+ counts=dict(value.counts),
277
+ file_sha256=dict(value.file_sha256),
278
+ )
279
+
280
+ return dict(
281
+ benchmark_id=self.benchmark_id,
282
+ split=self.split,
283
+ query_preparation=prepared(self.query_prepared),
284
+ corpus_preparation=prepared(self.corpus_prepared),
285
+ test_queries=len(self._examples),
286
+ scorer="ir_measures:nDCG@10,R@100",
287
+ ignore_identical_ids=self._ignore_identical_ids,
288
+ excluded_documents_policy="evaluator_metadata.excluded_document_ids_except_N/A",
289
+ )
290
+
291
+ def score(
292
+ self,
293
+ example: BenchmarkExample,
294
+ prediction: RetrievalPrediction | Mapping[str, float] | Sequence[str],
295
+ ) -> Mapping[str, float]:
296
+ if not isinstance(example, BenchmarkExample):
297
+ raise TypeError("example must be a BenchmarkExample")
298
+ if self._examples_by_id.get(example.example_id) is not example:
299
+ raise ValidationError(
300
+ "benchmark example does not belong to this prepared retrieval adapter"
301
+ )
302
+ if isinstance(prediction, RetrievalPrediction):
303
+ normalized = prediction
304
+ elif isinstance(prediction, Mapping):
305
+ normalized = RetrievalPrediction(prediction)
306
+ else:
307
+ normalized = RetrievalPrediction.from_ranked_ids(prediction)
308
+ relevance = example.evaluator_gold.get("relevance")
309
+ if not isinstance(relevance, Mapping):
310
+ raise ArtifactError("benchmark example does not contain retrieval qrels")
311
+ evaluator_metadata = example.evaluator_gold.get("evaluator_metadata", {})
312
+ if not isinstance(evaluator_metadata, Mapping): # pragma: no cover - construction invariant
313
+ raise ArtifactError("benchmark example evaluator metadata is invalid")
314
+ raw_excluded = evaluator_metadata.get("excluded_document_ids", ())
315
+ if not isinstance(raw_excluded, tuple): # pragma: no cover - construction invariant
316
+ raise ArtifactError("benchmark example excluded document IDs are invalid")
317
+ excluded = frozenset(item for item in raw_excluded if item != "N/A")
318
+ # BRIGHT's official get_scores removes excluded documents before
319
+ # truncation/evaluation. Apply the same boundary here so callers may
320
+ # submit raw retriever scores without accidentally changing ranks.
321
+ # BEIR's default evaluator also removes query/document pairs with an
322
+ # identical ID; this is material for ArguAna, whose corpus reuses most
323
+ # query IDs. Keep this profile-specific rather than applying it to
324
+ # unrelated retrieval suites.
325
+ evaluation_scores = {
326
+ document_id: score
327
+ for document_id, score in normalized.scores.items()
328
+ if document_id not in excluded
329
+ and not (self._ignore_identical_ids and document_id == example.example_id)
330
+ }
331
+ return retrieval_aggregates(
332
+ {example.example_id: relevance},
333
+ {example.example_id: evaluation_scores},
334
+ measures={
335
+ "ndcg_at_10": "nDCG@10",
336
+ "recall": "R@100",
337
+ },
338
+ )
339
+
340
+
341
+ def _records_by_id(path: Path, *, label: str) -> dict[str, dict[str, Any]]:
342
+ records: dict[str, dict[str, Any]] = {}
343
+ try:
344
+ with path.open(encoding="utf-8") as handle:
345
+ for line_number, raw in enumerate(handle, start=1):
346
+ if not raw.strip():
347
+ raise ArtifactError(f"{label} contains a blank line at {line_number}")
348
+ value = json.loads(raw)
349
+ if not isinstance(value, dict):
350
+ raise ArtifactError(f"{label} row {line_number} must be an object")
351
+ row_id = _required_text(value, "id", label=label)
352
+ if row_id in records:
353
+ raise ArtifactError(f"{label} contains duplicate ID {row_id!r}")
354
+ records[row_id] = value
355
+ except (OSError, UnicodeError, json.JSONDecodeError) as exc:
356
+ raise ArtifactError(f"{label} is not valid UTF-8 JSONL") from exc
357
+ if not records:
358
+ raise ArtifactError(f"{label} contains no records")
359
+ return records
360
+
361
+
362
+ def _required_text(record: Mapping[str, Any], key: str, *, label: str) -> str:
363
+ value = record.get(key)
364
+ if not isinstance(value, str) or not value.strip():
365
+ raise ArtifactError(f"{label} field {key!r} must be a non-empty string")
366
+ return value
367
+
368
+
369
+ def _validated_identity(value: str, *, label: str) -> None:
370
+ if not isinstance(value, str) or not value.strip():
371
+ raise ValidationError(f"{label} must be non-empty")
372
+
373
+
374
+ def _validate_prepared_identity(
375
+ prepared: PreparedBenchmark,
376
+ *,
377
+ benchmark_id: str,
378
+ split: str,
379
+ label: str,
380
+ require_complete: bool,
381
+ ) -> None:
382
+ if require_complete and not prepared.cell_id:
383
+ raise ArtifactError(f"{label} requires an explicit cell_id")
384
+ if require_complete and not prepared.split:
385
+ raise ArtifactError(f"{label} requires an explicit split")
386
+ if prepared.cell_id and prepared.cell_id != benchmark_id:
387
+ raise ArtifactError(f"{label} cell_id does not match adapter benchmark_id")
388
+ if prepared.split and prepared.split != split:
389
+ raise ArtifactError(f"{label} split does not match adapter split")
390
+
391
+
392
+ def _validate_named_prepared_identity(
393
+ prepared: PreparedBenchmark,
394
+ *,
395
+ benchmark_id: str,
396
+ split: str,
397
+ expected_asset_id: str,
398
+ expected_processor: str | None,
399
+ expected_split: str,
400
+ label: str,
401
+ ) -> None:
402
+ if split != expected_split:
403
+ raise ArtifactError(
404
+ f"named retrieval profile {benchmark_id!r} requires adapter split {expected_split!r}"
405
+ )
406
+ expected_fields = {
407
+ "asset_id": expected_asset_id,
408
+ "processor": expected_processor,
409
+ "cell_id": benchmark_id,
410
+ "split": expected_split,
411
+ }
412
+ for field, expected_value in expected_fields.items():
413
+ if getattr(prepared, field) != expected_value:
414
+ raise ArtifactError(f"{label} {field} does not match named profile {benchmark_id!r}")
415
+
416
+
417
+ def _visible_metadata(
418
+ value: Any,
419
+ *,
420
+ benchmark_id: str,
421
+ split: str,
422
+ require_source_split: bool,
423
+ ) -> Mapping[str, Any]:
424
+ if not isinstance(value, Mapping):
425
+ raise ArtifactError("prepared retrieval visible_metadata must be an object")
426
+ if value.get("benchmark_cell") != benchmark_id:
427
+ raise ArtifactError("prepared retrieval benchmark_cell does not match adapter benchmark_id")
428
+ source_split = value.get("source_split")
429
+ if require_source_split and source_split is None:
430
+ raise ArtifactError("prepared retrieval visible_metadata requires source_split")
431
+ if source_split is not None and source_split != split:
432
+ raise ArtifactError("prepared retrieval source_split does not match adapter split")
433
+ return _frozen_canonical_mapping(value, label="prepared retrieval visible_metadata")
434
+
435
+
436
+ def _excluded_document_ids(evaluator_metadata: Mapping[str, Any]) -> tuple[str, ...]:
437
+ value = evaluator_metadata.get("excluded_document_ids", [])
438
+ if not isinstance(value, list):
439
+ raise ArtifactError("prepared retrieval excluded_document_ids must be a JSON array")
440
+ if not all(isinstance(item, str) and item.strip() for item in value):
441
+ raise ArtifactError(
442
+ "prepared retrieval excluded_document_ids must contain non-empty strings"
443
+ )
444
+ normalized = tuple(item for item in value if item != "N/A")
445
+ if len(normalized) != len(set(normalized)):
446
+ raise ArtifactError("prepared retrieval excluded_document_ids must not contain duplicates")
447
+ return normalized
448
+
449
+
450
+ def _frozen_canonical_mapping(value: Mapping[str, Any], *, label: str) -> Mapping[str, Any]:
451
+ try:
452
+ frozen = freeze_mapping(value)
453
+ canonical_json(frozen)
454
+ except (TypeError, ValueError) as exc:
455
+ raise ArtifactError(f"{label} is not canonical: {exc}") from exc
456
+ return frozen
457
+
458
+
459
+ __all__ = ["PreparedRetrievalBenchmarkAdapter", "RetrievalPrediction"]