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,1312 @@
1
+ """Controlled, source-informed same-candidate execution path for R²AG.
2
+
3
+ The upstream implementation has two materially different stages:
4
+
5
+ 1. derive three retrieval features for every *already retrieved* document; and
6
+ 2. pass that tensor through a trained R²-Former/projection before replacing one
7
+ retrieval-marker embedding per document in the frozen reader.
8
+
9
+ AgentInputLab executes the deterministic first stage locally (or accepts the
10
+ official pre-computed feature fields) and delegates only the checkpoint-bound
11
+ neural stage to a pinned worker. The worker must echo every treatment-defining
12
+ hash and attest that it replaced exactly the intended marker embeddings.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import math
18
+ import re
19
+ from collections.abc import Mapping, Sequence
20
+ from dataclasses import asdict, dataclass
21
+ from enum import Enum
22
+ from typing import Any
23
+
24
+ from agentinputlab.backends.vector import DenseEmbedder
25
+ from agentinputlab.contracts import (
26
+ AlgorithmOutputError,
27
+ BudgetExceededError,
28
+ CompositeResult,
29
+ ContextBlock,
30
+ ExecutionTrace,
31
+ ExternalDependencyError,
32
+ FrozenAgentState,
33
+ InterventionContext,
34
+ SemanticFamily,
35
+ TraceEvent,
36
+ TracePhase,
37
+ ValidationError,
38
+ )
39
+ from agentinputlab.contracts.serialization import content_hash, freeze_mapping
40
+ from agentinputlab.integrations.external_workers import WorkerClient
41
+ from agentinputlab.integrations.external_workers.method import (
42
+ MethodWorkerRequest,
43
+ call_worker,
44
+ dependency_fingerprint,
45
+ finite_number,
46
+ mapping_sequence,
47
+ nonnegative_integer,
48
+ optional_text,
49
+ required_text,
50
+ resolve_worker,
51
+ string_tuple,
52
+ worker_fingerprint,
53
+ )
54
+ from agentinputlab.observability import external_usage_counters
55
+
56
+ R2AG_UPSTREAM_COMMIT = "61cfd1027c0101172fda701ec816bc18360b5bab"
57
+ R2AG_PROTOCOL = "agentinputlab.r2ag.v4"
58
+ R2AG_FEATURE_NAMES = ("rerank", "neighbor", "precedent")
59
+ _RUNTIME_DEPENDENCIES = {
60
+ "torch": "2.1.2",
61
+ "transformers": "4.40.2",
62
+ "sentence-transformers": "2.6.1",
63
+ }
64
+ _HEX64 = re.compile(r"^[0-9a-f]{64}$")
65
+ _IMMUTABLE_REVISION_ALIASES = frozenset({"default", "head", "latest", "main", "master"})
66
+ _FORBIDDEN_FINGERPRINT_TERMS = frozenset(
67
+ {
68
+ "answer",
69
+ "api",
70
+ "credential",
71
+ "expected",
72
+ "gold",
73
+ "groundtruth",
74
+ "label",
75
+ "oracle",
76
+ "password",
77
+ "reference",
78
+ "reward",
79
+ "secret",
80
+ "solution",
81
+ "supporting",
82
+ "target",
83
+ }
84
+ )
85
+ _CANDIDATE_POOL_KEYS = frozenset(
86
+ {"retriever", "corpus", "index", "top_k", "order", "content_sha256"}
87
+ )
88
+ _REPOSITORY_IDENTITY_REQUIRED = frozenset({"repository", "revision"})
89
+ _REPOSITORY_IDENTITY_OPTIONAL = frozenset({"manifest_sha256"})
90
+ _INDEX_IDENTITY_REQUIRED = frozenset({"algorithm", "revision"})
91
+ _INDEX_IDENTITY_OPTIONAL = frozenset({"manifest_sha256"})
92
+ _FEATURE_ARTIFACT_KEYS = frozenset({"repository", "revision", "sha256"})
93
+ _FEATURE_EMBEDDER_KEYS = frozenset({"kind", "fingerprint_sha256"})
94
+ _CANDIDATE_ORDER = "rerank_desc"
95
+
96
+ _READER_TEMPLATE = (
97
+ "Write a high-quality answer for the given question using only the provided "
98
+ "search results (some of which might be irrelevant). Only give me the answer "
99
+ "and do not output any other words. The similarity information is provided "
100
+ "in front of search results.\n\n"
101
+ "{search_results}\n\n"
102
+ "Only give me the answer and do not output any other words. \n"
103
+ "Question: {question}\n"
104
+ "Answer:"
105
+ )
106
+ _INSTRUCTION_WRAPPER = "### Instruction: \n{instruction}\n\n### Response:\n"
107
+
108
+ Vector = tuple[float, ...]
109
+ FeatureRow = tuple[float, float, float]
110
+
111
+
112
+ class R2AGFeatureSource(str, Enum):
113
+ """Where the official three-column retrieval tensor is produced."""
114
+
115
+ WORKER = "worker"
116
+ EMBEDDER = "embedder"
117
+ CANDIDATE_METADATA = "candidate_metadata"
118
+
119
+
120
+ def _pinned_revision(value: object, *, label: str) -> str:
121
+ if not isinstance(value, str) or not value.strip():
122
+ raise ValidationError(f"R²AG {label} must be a non-empty revision")
123
+ revision = value.strip()
124
+ if revision.lower() in _IMMUTABLE_REVISION_ALIASES:
125
+ raise ValidationError(f"R²AG {label} must be immutable")
126
+ return revision
127
+
128
+
129
+ def _sha256(value: object, *, label: str) -> str:
130
+ if not isinstance(value, str) or not _HEX64.fullmatch(value):
131
+ raise ValidationError(f"R²AG {label} must be a lowercase SHA-256 digest")
132
+ return value
133
+
134
+
135
+ @dataclass(frozen=True, slots=True)
136
+ class R2AGArtifactIdentity:
137
+ """Hash-bound source, checkpoint, reader, tokenizer, and feature identities.
138
+
139
+ This identity deliberately does not imply that AgentInputLab redistributes or
140
+ has benchmark-validated the mounted weights. When paired with the worker's
141
+ complete file-closure manifests, it hash-binds the mounted treatment without
142
+ asserting paper checkpoint or benchmark-result parity.
143
+ """
144
+
145
+ checkpoint_repository: str
146
+ checkpoint_revision: str
147
+ checkpoint_config_sha256: str
148
+ rformer_weights_sha256: str
149
+ projection_weights_sha256: str
150
+ checkpoint_num_documents: int
151
+ base_model_repository: str
152
+ base_model_revision: str
153
+ base_model_manifest_sha256: str
154
+ tokenizer_repository: str
155
+ tokenizer_revision: str
156
+ tokenizer_manifest_sha256: str
157
+ feature_schema_revision: str
158
+ feature_schema_sha256: str
159
+ source_manifest_sha256: str
160
+ compatibility_manifest_sha256: str
161
+ upstream_commit: str = R2AG_UPSTREAM_COMMIT
162
+
163
+ def __post_init__(self) -> None:
164
+ if self.upstream_commit != R2AG_UPSTREAM_COMMIT:
165
+ raise ValidationError("R²AG artifacts target an unsupported upstream commit")
166
+ for name in (
167
+ "checkpoint_repository",
168
+ "checkpoint_revision",
169
+ "base_model_repository",
170
+ "base_model_revision",
171
+ "tokenizer_repository",
172
+ "tokenizer_revision",
173
+ "feature_schema_revision",
174
+ ):
175
+ object.__setattr__(
176
+ self,
177
+ name,
178
+ _pinned_revision(getattr(self, name), label=name),
179
+ )
180
+ for name in (
181
+ "checkpoint_config_sha256",
182
+ "rformer_weights_sha256",
183
+ "projection_weights_sha256",
184
+ "base_model_manifest_sha256",
185
+ "tokenizer_manifest_sha256",
186
+ "feature_schema_sha256",
187
+ "source_manifest_sha256",
188
+ "compatibility_manifest_sha256",
189
+ ):
190
+ object.__setattr__(self, name, _sha256(getattr(self, name), label=name))
191
+ if (
192
+ isinstance(self.checkpoint_num_documents, bool)
193
+ or not isinstance(self.checkpoint_num_documents, int)
194
+ or self.checkpoint_num_documents < 2
195
+ or self.checkpoint_num_documents > 30
196
+ ):
197
+ raise ValidationError(
198
+ "R²AG checkpoint_num_documents must be an integer between 2 and 30"
199
+ )
200
+
201
+ def as_mapping(self) -> Mapping[str, Any]:
202
+ return freeze_mapping(asdict(self))
203
+
204
+ @property
205
+ def identity_sha256(self) -> str:
206
+ return content_hash(self.as_mapping())
207
+
208
+
209
+ @dataclass(frozen=True, slots=True)
210
+ class R2AGControls:
211
+ max_documents: int = 30
212
+ max_output_tokens: int = 2048
213
+ feature_source: R2AGFeatureSource = R2AGFeatureSource.WORKER
214
+ checkpoint_num_documents: int = 10
215
+ require_rerank_order: bool = True
216
+ numeric_tolerance: float = 1e-6
217
+ max_reader_chars: int = 2_000_000
218
+ retrieval_token: str = "<R>"
219
+ unknown_token: str = "<unk>"
220
+
221
+ def __post_init__(self) -> None:
222
+ for value in (self.max_output_tokens, self.max_reader_chars):
223
+ if isinstance(value, bool) or not isinstance(value, int) or value < 1:
224
+ raise ValidationError("R²AG document, output, and reader limits must be positive")
225
+ if (
226
+ isinstance(self.max_documents, bool)
227
+ or not isinstance(self.max_documents, int)
228
+ or self.max_documents < 2
229
+ ):
230
+ raise ValidationError("R²AG max_documents must be at least two")
231
+ if not isinstance(self.feature_source, R2AGFeatureSource):
232
+ raise ValidationError("R²AG feature_source must be an R2AGFeatureSource")
233
+ if (
234
+ isinstance(self.checkpoint_num_documents, bool)
235
+ or not isinstance(self.checkpoint_num_documents, int)
236
+ or self.checkpoint_num_documents < 2
237
+ or self.checkpoint_num_documents > self.max_documents
238
+ ):
239
+ raise ValidationError(
240
+ "R²AG checkpoint_num_documents must be between 2 and max_documents"
241
+ )
242
+ if self.require_rerank_order is not True:
243
+ raise ValidationError("R²AG controlled comparison requires descending rerank order")
244
+ if (
245
+ isinstance(self.numeric_tolerance, bool)
246
+ or not isinstance(self.numeric_tolerance, (int, float))
247
+ or not math.isfinite(self.numeric_tolerance)
248
+ or self.numeric_tolerance < 0
249
+ or self.numeric_tolerance > 1e-3
250
+ ):
251
+ raise ValidationError("R²AG numeric_tolerance must be between 0 and 1e-3")
252
+ for name in ("retrieval_token", "unknown_token"):
253
+ value = getattr(self, name)
254
+ if not isinstance(value, str) or not value:
255
+ raise ValidationError(f"R²AG {name} must not be empty")
256
+ if self.retrieval_token == self.unknown_token:
257
+ raise ValidationError("R²AG retrieval_token and unknown_token must be distinct")
258
+
259
+
260
+ @dataclass(slots=True)
261
+ class R2AGControlledWorker:
262
+ """Execute a controlled R²AG-shaped treatment on fixed candidates.
263
+
264
+ ``feature_source=EMBEDDER`` reproduces the formulas in the pinned upstream
265
+ ``retrieval/retrieval_utils.py`` without importing its CUDA-side-effectful
266
+ module. ``CANDIDATE_METADATA`` consumes the three fields emitted by the
267
+ reviewed feature-extraction scripts. ``WORKER`` retains the compatibility
268
+ path for deployments that compute those features in the pinned worker.
269
+ Complete closure verification hash-binds mounted artifacts; it does not
270
+ establish paper-checkpoint or benchmark-result parity.
271
+ """
272
+
273
+ artifacts: R2AGArtifactIdentity
274
+ client: WorkerClient | None = None
275
+ embedder: DenseEmbedder | None = None
276
+ controls: R2AGControls = R2AGControls()
277
+ allow_fixture_worker: bool = False
278
+ method_id: str = "r2ag"
279
+ release_id: str = "acquire.r2ag.controlled_same_candidates"
280
+ family: SemanticFamily = SemanticFamily.ACQUIRE
281
+
282
+ def __post_init__(self) -> None:
283
+ if not isinstance(self.artifacts, R2AGArtifactIdentity):
284
+ raise ValidationError("R²AG requires R2AGArtifactIdentity")
285
+ if not isinstance(self.controls, R2AGControls):
286
+ raise ValidationError("R²AG controls must be R2AGControls")
287
+ if self.controls.checkpoint_num_documents != self.artifacts.checkpoint_num_documents:
288
+ raise ValidationError(
289
+ "R²AG controls and artifact config must use the same checkpoint_num_documents"
290
+ )
291
+ if not isinstance(self.allow_fixture_worker, bool):
292
+ raise ValidationError("R²AG allow_fixture_worker must be boolean")
293
+
294
+ def run(self, state: FrozenAgentState, context: InterventionContext) -> CompositeResult:
295
+ if not state.query.strip():
296
+ raise ValidationError("R²AG requires a non-empty query")
297
+ if state.instruction.strip() or state.messages or state.tool_names:
298
+ raise ValidationError(
299
+ "R²AG controlled_same_candidates accepts query plus candidate context only"
300
+ )
301
+ candidate_ids = self._validate_candidates(state)
302
+ candidate_documents = _candidate_documents(state.context)
303
+ candidate_documents_hash = content_hash(candidate_documents)
304
+ candidate_order_hash = content_hash(candidate_ids)
305
+ candidate_pool_identity = _candidate_pool_fingerprint(
306
+ context,
307
+ candidate_documents=candidate_documents,
308
+ )
309
+ remaining_budget = _remaining_budget(state, context)
310
+ if state.budget.max_cost_usd is not None:
311
+ raise BudgetExceededError("R²AG external execution has no pre-call cost upper bound")
312
+ if remaining_budget["model_calls"] < 1:
313
+ raise BudgetExceededError("R²AG has no remaining reader model-call budget")
314
+ if remaining_budget["output_tokens"] < 1:
315
+ raise BudgetExceededError("R²AG has no remaining output-token budget")
316
+ context_tokens = remaining_budget["context_tokens"]
317
+ if context_tokens is not None and context_tokens <= 0:
318
+ raise BudgetExceededError("R²AG has no remaining context-token budget")
319
+ reader_instruction, reader_input = _build_reader_input(
320
+ state,
321
+ retrieval_token=self.controls.retrieval_token,
322
+ unknown_token=self.controls.unknown_token,
323
+ max_chars=self.controls.max_reader_chars,
324
+ )
325
+ expected_features, feature_dependencies = self._prepare_features(state, context)
326
+ feature_embedder_identity = feature_dependencies.get("feature_embedder")
327
+ feature_artifact_identity = feature_dependencies.get("feature_artifact")
328
+ expected_feature_hash = (
329
+ content_hash(expected_features) if expected_features is not None else ""
330
+ )
331
+ reader_instruction_hash = content_hash(reader_instruction)
332
+ reader_input_hash = content_hash(reader_input)
333
+
334
+ worker = resolve_worker(self.client, context, label="R²AG")
335
+ worker_identity = worker_fingerprint(worker, label="R²AG")
336
+ if worker_identity.get("runtime_dependencies") != _RUNTIME_DEPENDENCIES:
337
+ raise ExternalDependencyError(
338
+ "R²AG worker runtime dependency versions do not match the pinned profile"
339
+ )
340
+ artifact_mapping = self.artifacts.as_mapping()
341
+ request = MethodWorkerRequest(
342
+ method_id=self.method_id,
343
+ release_id=self.release_id,
344
+ upstream_commit=R2AG_UPSTREAM_COMMIT,
345
+ state_hash=state.state_hash,
346
+ payload={
347
+ "task_id": state.task_id,
348
+ "query": state.query,
349
+ "candidate_documents": candidate_documents,
350
+ "candidate_document_ids": candidate_ids,
351
+ "candidate_documents_sha256": candidate_documents_hash,
352
+ "candidate_order_sha256": candidate_order_hash,
353
+ "candidate_pool_fingerprint": candidate_pool_identity,
354
+ "candidate_pool_fingerprint_sha256": content_hash(candidate_pool_identity),
355
+ "artifacts": artifact_mapping,
356
+ "artifact_identity_sha256": self.artifacts.identity_sha256,
357
+ "features": (
358
+ _feature_mappings(expected_features) if expected_features is not None else None
359
+ ),
360
+ "feature_tensor_sha256": expected_feature_hash,
361
+ "feature_source": self.controls.feature_source.value,
362
+ "feature_names": R2AG_FEATURE_NAMES,
363
+ "feature_embedder_fingerprint": feature_embedder_identity,
364
+ "feature_embedder_fingerprint_sha256": content_hash(feature_embedder_identity),
365
+ "feature_artifact_fingerprint": feature_artifact_identity,
366
+ "feature_artifact_fingerprint_sha256": content_hash(feature_artifact_identity),
367
+ "reader_instruction": reader_instruction,
368
+ "reader_instruction_sha256": reader_instruction_hash,
369
+ "reader_input": reader_input,
370
+ "reader_input_sha256": reader_input_hash,
371
+ "controls": asdict(self.controls),
372
+ "remaining_budget": remaining_budget,
373
+ "seed": context.seed,
374
+ "execution_contract": {
375
+ "allow_training": False,
376
+ "allow_gold_metadata": False,
377
+ "require_source_verification": True,
378
+ "require_checkpoint_hash_verification": True,
379
+ "require_rformer_then_projection": True,
380
+ "replace_only_retrieval_marker_embeddings": True,
381
+ "check_budget_before_reader_call": True,
382
+ },
383
+ },
384
+ dependency_fingerprints={
385
+ "candidate_pool": candidate_pool_identity,
386
+ "worker": worker_identity,
387
+ "artifacts": artifact_mapping,
388
+ **feature_dependencies,
389
+ },
390
+ minimum_reservation={"model_calls": 1},
391
+ protocol_version=R2AG_PROTOCOL,
392
+ )
393
+ response = call_worker(worker, request)
394
+ payload = response.payload
395
+ returned_ids = string_tuple(
396
+ payload.get("candidate_document_ids"),
397
+ label="R²AG candidate_document_ids",
398
+ allow_empty=False,
399
+ unique=True,
400
+ )
401
+ if returned_ids != candidate_ids:
402
+ raise AlgorithmOutputError("R²AG worker changed the fixed candidate ordering")
403
+ _require_echo_hash(
404
+ payload,
405
+ "candidate_documents_sha256",
406
+ candidate_documents_hash,
407
+ )
408
+ _require_echo_hash(payload, "candidate_order_sha256", candidate_order_hash)
409
+ _require_echo_hash(
410
+ payload,
411
+ "candidate_pool_fingerprint_sha256",
412
+ content_hash(candidate_pool_identity),
413
+ )
414
+ returned_artifacts = payload.get("artifacts")
415
+ if not isinstance(returned_artifacts, Mapping) or dict(returned_artifacts) != dict(
416
+ artifact_mapping
417
+ ):
418
+ raise AlgorithmOutputError("R²AG worker artifact identity mismatch")
419
+ _require_echo_hash(
420
+ payload,
421
+ "artifact_identity_sha256",
422
+ self.artifacts.identity_sha256,
423
+ )
424
+ worker_num_k = nonnegative_integer(
425
+ payload.get("worker_config_num_k"),
426
+ label="R²AG worker_config_num_k",
427
+ )
428
+ if worker_num_k != self.controls.checkpoint_num_documents:
429
+ raise AlgorithmOutputError(
430
+ "R²AG worker config.num_k does not match checkpoint candidate count"
431
+ )
432
+
433
+ features = _parse_features(payload.get("features"), expected_count=len(candidate_ids))
434
+ _validate_feature_range_and_order(
435
+ features,
436
+ require_rerank_order=self.controls.require_rerank_order,
437
+ tolerance=float(self.controls.numeric_tolerance),
438
+ )
439
+ if expected_features is not None:
440
+ _require_same_features(
441
+ expected_features,
442
+ features,
443
+ tolerance=float(self.controls.numeric_tolerance),
444
+ )
445
+ actual_feature_hash = content_hash(features)
446
+ _require_echo_hash(
447
+ payload,
448
+ "feature_tensor_sha256",
449
+ expected_feature_hash if expected_features is not None else actual_feature_hash,
450
+ )
451
+ _require_echo_hash(
452
+ payload,
453
+ "feature_embedder_fingerprint_sha256",
454
+ content_hash(feature_embedder_identity),
455
+ )
456
+ _require_echo_hash(
457
+ payload,
458
+ "feature_artifact_fingerprint_sha256",
459
+ content_hash(feature_artifact_identity),
460
+ )
461
+ _require_echo_hash(
462
+ payload,
463
+ "reader_instruction_sha256",
464
+ reader_instruction_hash,
465
+ )
466
+ _require_echo_hash(payload, "reader_input_sha256", reader_input_hash)
467
+ r2former_output_hash = _sha256_response(
468
+ payload,
469
+ "r2former_output_sha256",
470
+ )
471
+ projection_output_hash = _sha256_response(
472
+ payload,
473
+ "projection_output_sha256",
474
+ )
475
+
476
+ r_token_count = nonnegative_integer(
477
+ payload.get("r_token_count"),
478
+ label="R²AG r_token_count",
479
+ )
480
+ if r_token_count != len(candidate_ids):
481
+ raise AlgorithmOutputError("R²AG requires exactly one <R> token per document")
482
+ raw_positions = payload.get("r_token_positions")
483
+ if isinstance(raw_positions, (str, bytes)) or not isinstance(raw_positions, Sequence):
484
+ raise AlgorithmOutputError("R²AG r_token_positions must be a sequence")
485
+ r_token_positions = tuple(
486
+ nonnegative_integer(item, label="R²AG r_token_position") for item in raw_positions
487
+ )
488
+ if (
489
+ len(r_token_positions) != len(candidate_ids)
490
+ or len(r_token_positions) != len(set(r_token_positions))
491
+ or r_token_positions != tuple(sorted(r_token_positions))
492
+ ):
493
+ raise AlgorithmOutputError("R²AG requires one unique ordered <R> position per document")
494
+ if payload.get("non_retrieval_unk_positions_modified") is not False:
495
+ raise AlgorithmOutputError(
496
+ "R²AG worker must attest that non-retrieval unknown tokens were untouched"
497
+ )
498
+ fixture_mode, execution_evidence = _validate_runtime_attestation(
499
+ payload.get("runtime_attestation"),
500
+ artifacts=self.artifacts,
501
+ expected_num_k=self.controls.checkpoint_num_documents,
502
+ allow_fixture=self.allow_fixture_worker,
503
+ )
504
+ _validate_usage(
505
+ response.usage,
506
+ remaining_budget=remaining_budget,
507
+ controls=self.controls,
508
+ )
509
+ answer = optional_text(payload, "answer", label="R²AG response")
510
+ if not answer.strip():
511
+ raise AlgorithmOutputError("R²AG custom model must return a final answer")
512
+
513
+ conditioned_blocks = tuple(
514
+ ContextBlock(
515
+ block_id=block.block_id,
516
+ text=block.text,
517
+ source=block.source,
518
+ score=block.score,
519
+ metadata={
520
+ **_safe_candidate_metadata(block),
521
+ "r2ag_features": feature,
522
+ "r2ag_feature_names": R2AG_FEATURE_NAMES,
523
+ "r2ag_feature_schema_revision": self.artifacts.feature_schema_revision,
524
+ "r2ag_candidate_index": index,
525
+ },
526
+ )
527
+ for index, (block, feature) in enumerate(zip(state.context, features, strict=True))
528
+ )
529
+ trace = ExecutionTrace(
530
+ method_id=self.method_id,
531
+ release_id=self.release_id,
532
+ events=(
533
+ TraceEvent(
534
+ TracePhase.PREPARE,
535
+ "fixed_candidates_and_reader_input",
536
+ {
537
+ "document_ids": candidate_ids,
538
+ "base_model_revision": self.artifacts.base_model_revision,
539
+ "checkpoint_num_documents": self.controls.checkpoint_num_documents,
540
+ "candidate_documents_sha256": candidate_documents_hash,
541
+ "candidate_pool_fingerprint_sha256": content_hash(candidate_pool_identity),
542
+ "reader_instruction_sha256": reader_instruction_hash,
543
+ "reader_input_sha256": reader_input_hash,
544
+ },
545
+ ),
546
+ TraceEvent(
547
+ TracePhase.OBSERVE,
548
+ "retrieval_feature_tensor",
549
+ {
550
+ "shape": (len(features), len(R2AG_FEATURE_NAMES)),
551
+ "features": features,
552
+ "feature_names": R2AG_FEATURE_NAMES,
553
+ "feature_source": self.controls.feature_source.value,
554
+ "feature_tensor_sha256": actual_feature_hash,
555
+ "feature_schema_revision": self.artifacts.feature_schema_revision,
556
+ },
557
+ ),
558
+ TraceEvent(
559
+ TracePhase.FINALIZE,
560
+ "custom_model_output",
561
+ {
562
+ "r2former_output_sha256": r2former_output_hash,
563
+ "projection_output_sha256": projection_output_hash,
564
+ "r_token_count": r_token_count,
565
+ "r_token_positions": r_token_positions,
566
+ "answer": answer,
567
+ "answer_is_intervention_input": False,
568
+ },
569
+ ),
570
+ ),
571
+ counters={
572
+ **external_usage_counters(response.usage),
573
+ "worker_calls": 1,
574
+ "embedding_calls": response.usage.embedding_calls
575
+ + (1 if self.controls.feature_source is R2AGFeatureSource.EMBEDDER else 0),
576
+ "conditioned_documents": len(candidate_ids),
577
+ "retrieval_feature_values": len(candidate_ids) * len(R2AG_FEATURE_NAMES),
578
+ },
579
+ )
580
+ treatment_identity = content_hash(
581
+ {
582
+ "upstream_commit": R2AG_UPSTREAM_COMMIT,
583
+ "release_id": self.release_id,
584
+ "artifacts": artifact_mapping,
585
+ "controls": asdict(self.controls),
586
+ "candidate_pool": candidate_pool_identity,
587
+ "candidate_documents_sha256": candidate_documents_hash,
588
+ "worker": worker_identity,
589
+ "fixture_mode": fixture_mode,
590
+ "execution_evidence": execution_evidence,
591
+ **feature_dependencies,
592
+ }
593
+ )
594
+ return CompositeResult(
595
+ method_id=self.method_id,
596
+ release_id=self.release_id,
597
+ source_state_hash=state.state_hash,
598
+ final_answer=answer,
599
+ evidence=conditioned_blocks,
600
+ trace=trace,
601
+ implementation_identity=(
602
+ f"controlled_source_informed:yefd/RRAG@{R2AG_UPSTREAM_COMMIT}"
603
+ ),
604
+ profile_kind="factorial_adapter",
605
+ metadata={
606
+ "implementation_origin": "controlled_source_informed_with_verified_worker",
607
+ "paper_checkpoint_parity": False,
608
+ "fixture_mode": fixture_mode,
609
+ "execution_evidence": execution_evidence,
610
+ "same_candidate_order": True,
611
+ "requires_custom_hidden_state_model": True,
612
+ "feature_source": self.controls.feature_source.value,
613
+ "feature_tensor_sha256": actual_feature_hash,
614
+ "reader_instruction_sha256": reader_instruction_hash,
615
+ "reader_input_sha256": reader_input_hash,
616
+ "r2former_output_sha256": r2former_output_hash,
617
+ "projection_output_sha256": projection_output_hash,
618
+ "artifacts": artifact_mapping,
619
+ "artifact_identity_sha256": self.artifacts.identity_sha256,
620
+ "checkpoint_revision": self.artifacts.checkpoint_revision,
621
+ "feature_schema_revision": self.artifacts.feature_schema_revision,
622
+ "base_model_revision": self.artifacts.base_model_revision,
623
+ "r_token_positions": r_token_positions,
624
+ "candidate_pool_fingerprint": candidate_pool_identity,
625
+ "candidate_documents_sha256": candidate_documents_hash,
626
+ "candidate_order_sha256": candidate_order_hash,
627
+ "worker_fingerprint": worker_identity,
628
+ "treatment_identity_sha256": treatment_identity,
629
+ **feature_dependencies,
630
+ },
631
+ )
632
+
633
+ def _validate_candidates(self, state: FrozenAgentState) -> tuple[str, ...]:
634
+ if not state.context:
635
+ raise ValidationError("R²AG requires a frozen candidate-document context")
636
+ if len(state.context) > self.controls.max_documents:
637
+ raise ValidationError("R²AG candidate set exceeds max_documents")
638
+ if len(state.context) != self.controls.checkpoint_num_documents:
639
+ raise ValidationError(
640
+ "R²AG candidate count must match checkpoint_num_documents exactly"
641
+ )
642
+ candidate_ids = tuple(block.block_id for block in state.context)
643
+ if any(not value for value in candidate_ids) or len(candidate_ids) != len(
644
+ set(candidate_ids)
645
+ ):
646
+ raise ValidationError("R²AG candidates require unique non-empty document IDs")
647
+ return candidate_ids
648
+
649
+ def _prepare_features(
650
+ self,
651
+ state: FrozenAgentState,
652
+ context: InterventionContext,
653
+ ) -> tuple[tuple[FeatureRow, ...] | None, Mapping[str, Any]]:
654
+ source = self.controls.feature_source
655
+ if source is R2AGFeatureSource.WORKER:
656
+ if self.embedder is not None:
657
+ raise ValidationError(
658
+ "R²AG worker feature_source cannot also receive a constructor embedder"
659
+ )
660
+ return None, freeze_mapping({})
661
+ if source is R2AGFeatureSource.CANDIDATE_METADATA:
662
+ fingerprint = context.run_config.get("r2ag_feature_artifact_fingerprint")
663
+ if not isinstance(fingerprint, Mapping):
664
+ raise ExternalDependencyError(
665
+ "R²AG candidate_metadata features require "
666
+ "run_config.r2ag_feature_artifact_fingerprint"
667
+ )
668
+ frozen_fingerprint = _feature_artifact_identity(
669
+ fingerprint,
670
+ label="R²AG feature artifact fingerprint",
671
+ )
672
+ features = _features_from_metadata(state.context)
673
+ _validate_feature_range_and_order(
674
+ features,
675
+ require_rerank_order=self.controls.require_rerank_order,
676
+ tolerance=float(self.controls.numeric_tolerance),
677
+ )
678
+ return features, freeze_mapping({"feature_artifact": frozen_fingerprint})
679
+
680
+ configured = self.embedder
681
+ injected = context.dense_embedder
682
+ if configured is not None and injected is not None and configured is not injected:
683
+ raise ValidationError(
684
+ "R²AG embedder is ambiguous; configure it either on the method or context"
685
+ )
686
+ embedder = injected if injected is not None else configured
687
+ if not isinstance(embedder, DenseEmbedder):
688
+ raise ExternalDependencyError(
689
+ "R²AG embedder feature_source requires an injected DenseEmbedder"
690
+ )
691
+ documents = tuple(_document_for_embedding(block) for block in state.context)
692
+ vectors = _validate_vectors(
693
+ embedder.embed((state.query, *documents)),
694
+ expected_count=len(documents) + 1,
695
+ )
696
+ features = _retrieval_features(vectors[0], vectors[1:])
697
+ _validate_feature_range_and_order(
698
+ features,
699
+ require_rerank_order=self.controls.require_rerank_order,
700
+ tolerance=float(self.controls.numeric_tolerance),
701
+ )
702
+ raw_embedder_identity = dependency_fingerprint(embedder, label="R²AG embedder")
703
+ _reject_forbidden_fingerprint_keys(
704
+ raw_embedder_identity,
705
+ label="R²AG embedder fingerprint",
706
+ )
707
+ feature_embedder_identity = freeze_mapping(
708
+ {
709
+ "kind": "dense_embedder",
710
+ "fingerprint_sha256": content_hash(raw_embedder_identity),
711
+ }
712
+ )
713
+ return features, freeze_mapping({"feature_embedder": feature_embedder_identity})
714
+
715
+
716
+ def _build_reader_input(
717
+ state: FrozenAgentState,
718
+ *,
719
+ retrieval_token: str,
720
+ unknown_token: str,
721
+ max_chars: int,
722
+ ) -> tuple[str, str]:
723
+ values = (state.query, *(block.text for block in state.context))
724
+ if any(retrieval_token in value or unknown_token in value for value in values):
725
+ raise ValidationError("R²AG query/documents must not contain retrieval marker tokens")
726
+ formatted_documents: list[str] = []
727
+ for index, block in enumerate(state.context, start=1):
728
+ title = block.metadata.get("title", "")
729
+ if title is None:
730
+ title = ""
731
+ if not isinstance(title, str):
732
+ raise ValidationError("R²AG candidate metadata title must be text")
733
+ if retrieval_token in title or unknown_token in title:
734
+ raise ValidationError("R²AG document titles must not contain retrieval marker tokens")
735
+ formatted_documents.append(
736
+ f"[{index}]similarity: {retrieval_token}(Title: {title}) {block.text}"
737
+ )
738
+ instruction = _READER_TEMPLATE.format(
739
+ search_results="\n".join(formatted_documents),
740
+ question=state.query,
741
+ )
742
+ if instruction.count(retrieval_token) != len(state.context):
743
+ raise ValidationError("R²AG reader instruction must contain one <R> marker per document")
744
+ reader_input = _INSTRUCTION_WRAPPER.format(instruction=instruction).replace(
745
+ retrieval_token,
746
+ unknown_token,
747
+ )
748
+ if reader_input.count(unknown_token) != len(state.context):
749
+ raise ValidationError("R²AG model input must contain one unknown marker per document")
750
+ if len(reader_input) > max_chars:
751
+ raise ValidationError("R²AG reader input exceeds max_reader_chars")
752
+ return instruction, reader_input
753
+
754
+
755
+ def _candidate_documents(context: Sequence[ContextBlock]) -> tuple[Mapping[str, Any], ...]:
756
+ """Build the only candidate DTO allowed to cross the worker boundary.
757
+
758
+ Arbitrary ``ContextBlock.metadata`` is intentionally not copied. In
759
+ particular, benchmark labels such as ``is_supporting`` and ``gold_answer``
760
+ cannot reach the neural worker through this path.
761
+ """
762
+
763
+ rows: list[Mapping[str, Any]] = []
764
+ for index, block in enumerate(context):
765
+ title = block.metadata.get("title", "")
766
+ corpus_revision = block.metadata.get("corpus_revision", "")
767
+ if title is None:
768
+ title = ""
769
+ if corpus_revision is None:
770
+ corpus_revision = ""
771
+ if not isinstance(title, str) or not isinstance(corpus_revision, str):
772
+ raise ValidationError(f"R²AG candidate {index} title/corpus_revision must be text")
773
+ score = block.score
774
+ if score is not None and (
775
+ isinstance(score, bool)
776
+ or not isinstance(score, (int, float))
777
+ or not math.isfinite(float(score))
778
+ ):
779
+ raise ValidationError(f"R²AG candidate {index} score must be finite or None")
780
+ rows.append(
781
+ freeze_mapping(
782
+ {
783
+ "document_id": block.block_id,
784
+ "text": block.text,
785
+ "title": title,
786
+ "source": block.source,
787
+ "score": None if score is None else float(score),
788
+ "corpus_revision": corpus_revision,
789
+ }
790
+ )
791
+ )
792
+ return tuple(rows)
793
+
794
+
795
+ def _safe_candidate_metadata(block: ContextBlock) -> Mapping[str, str]:
796
+ """Retain only non-oracle provenance in the materialized evidence."""
797
+
798
+ title = block.metadata.get("title", "")
799
+ corpus_revision = block.metadata.get("corpus_revision", "")
800
+ if title is None:
801
+ title = ""
802
+ if corpus_revision is None:
803
+ corpus_revision = ""
804
+ if not isinstance(title, str) or not isinstance(corpus_revision, str):
805
+ raise ValidationError("R²AG title/corpus_revision metadata must be text")
806
+ return freeze_mapping(
807
+ {
808
+ "title": title,
809
+ "corpus_revision": corpus_revision,
810
+ }
811
+ )
812
+
813
+
814
+ def _candidate_pool_fingerprint(
815
+ context: InterventionContext,
816
+ *,
817
+ candidate_documents: Sequence[Mapping[str, Any]],
818
+ ) -> Mapping[str, Any]:
819
+ value = context.run_config.get("candidate_pool_fingerprint")
820
+ if value is None:
821
+ raise ExternalDependencyError(
822
+ "R²AG requires run_config.candidate_pool_fingerprint for every feature source"
823
+ )
824
+ if not isinstance(value, Mapping) or set(value) != _CANDIDATE_POOL_KEYS:
825
+ raise ValidationError(
826
+ "R²AG candidate_pool_fingerprint must contain exactly retriever, corpus, "
827
+ "index, top_k, order, and content_sha256"
828
+ )
829
+ _reject_forbidden_fingerprint_keys(value, label="R²AG candidate pool fingerprint")
830
+ retriever = _repository_identity(
831
+ value.get("retriever"),
832
+ label="R²AG candidate_pool_fingerprint.retriever",
833
+ )
834
+ corpus = _repository_identity(
835
+ value.get("corpus"),
836
+ label="R²AG candidate_pool_fingerprint.corpus",
837
+ )
838
+ index = _index_identity(
839
+ value.get("index"),
840
+ label="R²AG candidate_pool_fingerprint.index",
841
+ )
842
+ top_k = value.get("top_k")
843
+ if isinstance(top_k, bool) or not isinstance(top_k, int) or top_k < 1:
844
+ raise ValidationError("R²AG candidate_pool_fingerprint.top_k must be positive")
845
+ if top_k != len(candidate_documents):
846
+ raise ValidationError(
847
+ "R²AG candidate_pool_fingerprint.top_k must equal the fixed candidate count"
848
+ )
849
+ if value.get("order") != _CANDIDATE_ORDER:
850
+ raise ValidationError("R²AG candidate_pool_fingerprint.order must be rerank_desc")
851
+ expected_content = content_hash(tuple(candidate_documents))
852
+ if value.get("content_sha256") != expected_content:
853
+ raise ValidationError("R²AG candidate_pool_fingerprint content hash mismatch")
854
+ try:
855
+ return freeze_mapping(
856
+ {
857
+ "retriever": retriever,
858
+ "corpus": corpus,
859
+ "index": index,
860
+ "top_k": top_k,
861
+ "order": _CANDIDATE_ORDER,
862
+ "content_sha256": expected_content,
863
+ }
864
+ )
865
+ except TypeError as exc:
866
+ raise ValidationError("R²AG candidate_pool_fingerprint is not canonical") from exc
867
+
868
+
869
+ def _repository_identity(value: object, *, label: str) -> Mapping[str, str]:
870
+ if not isinstance(value, Mapping):
871
+ raise ValidationError(f"{label} must be a mapping")
872
+ _reject_forbidden_fingerprint_keys(value, label=label)
873
+ keys = set(value)
874
+ allowed = _REPOSITORY_IDENTITY_REQUIRED | _REPOSITORY_IDENTITY_OPTIONAL
875
+ if not _REPOSITORY_IDENTITY_REQUIRED.issubset(keys) or not keys.issubset(allowed):
876
+ raise ValidationError(
877
+ f"{label} must contain repository/revision and optional manifest_sha256 only"
878
+ )
879
+ repository = value.get("repository")
880
+ if not isinstance(repository, str) or not repository.strip():
881
+ raise ValidationError(f"{label}.repository must be non-empty text")
882
+ revision = _pinned_revision(value.get("revision"), label=f"{label}.revision")
883
+ identity: dict[str, str] = {
884
+ "repository": repository.strip(),
885
+ "revision": revision,
886
+ }
887
+ if "manifest_sha256" in value:
888
+ identity["manifest_sha256"] = _sha256(
889
+ value.get("manifest_sha256"),
890
+ label=f"{label}.manifest_sha256",
891
+ )
892
+ return freeze_mapping(identity)
893
+
894
+
895
+ def _index_identity(value: object, *, label: str) -> Mapping[str, str]:
896
+ if not isinstance(value, Mapping):
897
+ raise ValidationError(f"{label} must be a mapping")
898
+ _reject_forbidden_fingerprint_keys(value, label=label)
899
+ keys = set(value)
900
+ allowed = _INDEX_IDENTITY_REQUIRED | _INDEX_IDENTITY_OPTIONAL
901
+ if not _INDEX_IDENTITY_REQUIRED.issubset(keys) or not keys.issubset(allowed):
902
+ raise ValidationError(
903
+ f"{label} must contain algorithm/revision and optional manifest_sha256 only"
904
+ )
905
+ algorithm = value.get("algorithm")
906
+ if not isinstance(algorithm, str) or not algorithm.strip():
907
+ raise ValidationError(f"{label}.algorithm must be non-empty text")
908
+ revision = _pinned_revision(value.get("revision"), label=f"{label}.revision")
909
+ identity: dict[str, str] = {
910
+ "algorithm": algorithm.strip(),
911
+ "revision": revision,
912
+ }
913
+ if "manifest_sha256" in value:
914
+ identity["manifest_sha256"] = _sha256(
915
+ value.get("manifest_sha256"),
916
+ label=f"{label}.manifest_sha256",
917
+ )
918
+ return freeze_mapping(identity)
919
+
920
+
921
+ def _feature_artifact_identity(value: object, *, label: str) -> Mapping[str, str]:
922
+ if not isinstance(value, Mapping):
923
+ raise ValidationError(f"{label} must contain exactly repository, revision, and sha256")
924
+ _reject_forbidden_fingerprint_keys(value, label=label)
925
+ if set(value) != _FEATURE_ARTIFACT_KEYS:
926
+ raise ValidationError(f"{label} must contain exactly repository, revision, and sha256")
927
+ repository = value.get("repository")
928
+ if not isinstance(repository, str) or not repository.strip():
929
+ raise ValidationError(f"{label}.repository must be non-empty text")
930
+ return freeze_mapping(
931
+ {
932
+ "repository": repository.strip(),
933
+ "revision": _pinned_revision(value.get("revision"), label=f"{label}.revision"),
934
+ "sha256": _sha256(value.get("sha256"), label=f"{label}.sha256"),
935
+ }
936
+ )
937
+
938
+
939
+ def _reject_forbidden_fingerprint_keys(value: object, *, label: str) -> None:
940
+ if isinstance(value, Mapping):
941
+ for key, nested in value.items():
942
+ if not isinstance(key, str):
943
+ raise ValidationError(f"{label} keys must be strings")
944
+ terms = tuple(re.findall(r"[a-z0-9]+", key.lower()))
945
+ compact = "".join(terms)
946
+ if any(term in _FORBIDDEN_FINGERPRINT_TERMS for term in (*terms, compact)):
947
+ raise ValidationError(f"{label} contains forbidden metadata key {key!r}")
948
+ _reject_forbidden_fingerprint_keys(nested, label=label)
949
+ elif isinstance(value, Sequence) and not isinstance(value, (str, bytes)):
950
+ for nested in value:
951
+ _reject_forbidden_fingerprint_keys(nested, label=label)
952
+
953
+
954
+ def _document_for_embedding(block: ContextBlock) -> str:
955
+ title = block.metadata.get("title", "")
956
+ if title is None:
957
+ title = ""
958
+ if not isinstance(title, str):
959
+ raise ValidationError("R²AG candidate metadata title must be text")
960
+ return f"Title: {title}\n{block.text}"
961
+
962
+
963
+ def _validate_vectors(
964
+ value: Sequence[Sequence[float]],
965
+ *,
966
+ expected_count: int,
967
+ ) -> tuple[Vector, ...]:
968
+ if isinstance(value, (str, bytes)) or not isinstance(value, Sequence):
969
+ raise AlgorithmOutputError("R²AG embedder returned a non-sequence")
970
+ try:
971
+ vectors = tuple(tuple(float(item) for item in row) for row in value)
972
+ except (TypeError, ValueError, OverflowError) as exc:
973
+ raise AlgorithmOutputError("R²AG embedder returned non-numeric vectors") from exc
974
+ if len(vectors) != expected_count:
975
+ raise AlgorithmOutputError(
976
+ f"R²AG embedder returned {len(vectors)} vectors; expected {expected_count}"
977
+ )
978
+ if not vectors or not vectors[0]:
979
+ raise AlgorithmOutputError("R²AG embeddings require a non-zero dimension")
980
+ dimension = len(vectors[0])
981
+ for vector in vectors:
982
+ if len(vector) != dimension:
983
+ raise AlgorithmOutputError("R²AG embeddings have inconsistent dimensions")
984
+ if not all(math.isfinite(item) for item in vector):
985
+ raise AlgorithmOutputError("R²AG embeddings must contain only finite values")
986
+ if _norm(vector) == 0:
987
+ raise AlgorithmOutputError("R²AG embeddings must not contain zero vectors")
988
+ return vectors
989
+
990
+
991
+ def compute_r2ag_retrieval_features(
992
+ query: Sequence[float],
993
+ documents: Sequence[Sequence[float]],
994
+ ) -> tuple[Mapping[str, float], ...]:
995
+ """Compute the three retrieval features from the pinned upstream formulas.
996
+
997
+ The public wrapper keeps common-support runtimes on the same reviewed
998
+ implementation used by the controlled worker while returning named rows.
999
+ """
1000
+
1001
+ try:
1002
+ query_vector = tuple(float(value) for value in query)
1003
+ document_vectors = tuple(
1004
+ tuple(float(value) for value in document) for document in documents
1005
+ )
1006
+ except (TypeError, ValueError, OverflowError) as exc:
1007
+ raise ValidationError("R²AG retrieval features require numeric vectors") from exc
1008
+ if not query_vector or len(document_vectors) < 2:
1009
+ raise ValidationError("R²AG retrieval features require a query and two documents")
1010
+ dimension = len(query_vector)
1011
+ if any(
1012
+ len(vector) != dimension
1013
+ or not all(math.isfinite(value) for value in vector)
1014
+ or _norm(vector) == 0
1015
+ for vector in (query_vector, *document_vectors)
1016
+ ):
1017
+ raise ValidationError("R²AG retrieval feature vectors are invalid")
1018
+ rows = _retrieval_features(query_vector, document_vectors)
1019
+ return tuple(freeze_mapping(dict(zip(R2AG_FEATURE_NAMES, row, strict=True))) for row in rows)
1020
+
1021
+
1022
+ def _retrieval_features(query: Vector, documents: Sequence[Vector]) -> tuple[FeatureRow, ...]:
1023
+ if len(documents) < 2:
1024
+ raise ValidationError("R²AG feature extraction requires at least two documents")
1025
+ rerank = tuple(_cosine(query, document) for document in documents)
1026
+ neighbor: list[float] = []
1027
+ for index, document in enumerate(documents):
1028
+ if index == 0:
1029
+ value = _cosine(document, documents[1])
1030
+ elif index == len(documents) - 1:
1031
+ value = _cosine(documents[-2], document)
1032
+ else:
1033
+ value = (
1034
+ _cosine(document, documents[index - 1]) + _cosine(document, documents[index + 1])
1035
+ ) / 2
1036
+ neighbor.append(value)
1037
+
1038
+ precedent = [1.0]
1039
+ for index in range(1, len(documents)):
1040
+ prior_scores = rerank[:index]
1041
+ maximum = max(prior_scores)
1042
+ unnormalized = tuple(math.exp(score - maximum) for score in prior_scores)
1043
+ denominator = sum(unnormalized)
1044
+ weights = tuple(value / denominator for value in unnormalized)
1045
+ weighted_precedent = tuple(
1046
+ sum(weights[row] * documents[row][column] for row in range(index))
1047
+ for column in range(len(documents[0]))
1048
+ )
1049
+ precedent.append(_cosine(documents[index], weighted_precedent))
1050
+ return tuple(
1051
+ (rerank[index], neighbor[index], precedent[index]) for index in range(len(documents))
1052
+ )
1053
+
1054
+
1055
+ def _cosine(left: Sequence[float], right: Sequence[float]) -> float:
1056
+ denominator = _norm(left) * _norm(right)
1057
+ if denominator == 0:
1058
+ raise AlgorithmOutputError("R²AG cosine similarity received a zero vector")
1059
+ value = sum(a * b for a, b in zip(left, right, strict=True)) / denominator
1060
+ if not math.isfinite(value):
1061
+ raise AlgorithmOutputError("R²AG cosine similarity is not finite")
1062
+ return max(-1.0, min(1.0, value))
1063
+
1064
+
1065
+ def _norm(vector: Sequence[float]) -> float:
1066
+ return math.sqrt(sum(value * value for value in vector))
1067
+
1068
+
1069
+ def _features_from_metadata(context: Sequence[ContextBlock]) -> tuple[FeatureRow, ...]:
1070
+ rows: list[FeatureRow] = []
1071
+ official_names = (
1072
+ "rerank_score",
1073
+ "rerank_nb_score",
1074
+ "rerank_precedent_score",
1075
+ )
1076
+ for index, block in enumerate(context):
1077
+ metadata = block.metadata
1078
+ if all(name in metadata for name in official_names):
1079
+ raw = tuple(metadata[name] for name in official_names)
1080
+ else:
1081
+ normalized = metadata.get("r2ag_features")
1082
+ if not isinstance(normalized, Mapping) or set(normalized) != set(R2AG_FEATURE_NAMES):
1083
+ raise ValidationError(
1084
+ f"R²AG candidate {index} lacks the official three retrieval features"
1085
+ )
1086
+ raw = tuple(normalized[name] for name in R2AG_FEATURE_NAMES)
1087
+ try:
1088
+ row = tuple(
1089
+ _metadata_number(value, label=f"R²AG candidate {index} feature") for value in raw
1090
+ )
1091
+ except (TypeError, ValueError, OverflowError) as exc:
1092
+ raise ValidationError(f"R²AG candidate {index} has invalid retrieval features") from exc
1093
+ rows.append((row[0], row[1], row[2]))
1094
+ return tuple(rows)
1095
+
1096
+
1097
+ def _metadata_number(value: object, *, label: str) -> float:
1098
+ if isinstance(value, bool) or not isinstance(value, (int, float)):
1099
+ raise TypeError(f"{label} must be numeric")
1100
+ result = float(value)
1101
+ if not math.isfinite(result):
1102
+ raise ValueError(f"{label} must be finite")
1103
+ return result
1104
+
1105
+
1106
+ def _parse_features(value: object, *, expected_count: int) -> tuple[FeatureRow, ...]:
1107
+ rows = mapping_sequence(value, label="R²AG features")
1108
+ if len(rows) != expected_count:
1109
+ raise AlgorithmOutputError("R²AG feature row count does not match candidates")
1110
+ parsed: list[FeatureRow] = []
1111
+ for index, row in enumerate(rows):
1112
+ if set(row) != set(R2AG_FEATURE_NAMES):
1113
+ raise AlgorithmOutputError(
1114
+ "R²AG feature rows must contain rerank, neighbor, and precedent"
1115
+ )
1116
+ values = tuple(
1117
+ finite_number(row[name], label=f"R²AG feature {index}.{name}")
1118
+ for name in R2AG_FEATURE_NAMES
1119
+ )
1120
+ parsed.append((values[0], values[1], values[2]))
1121
+ return tuple(parsed)
1122
+
1123
+
1124
+ def _feature_mappings(features: Sequence[FeatureRow]) -> tuple[Mapping[str, float], ...]:
1125
+ return tuple(
1126
+ freeze_mapping(dict(zip(R2AG_FEATURE_NAMES, row, strict=True))) for row in features
1127
+ )
1128
+
1129
+
1130
+ def _validate_feature_range_and_order(
1131
+ features: Sequence[FeatureRow],
1132
+ *,
1133
+ require_rerank_order: bool,
1134
+ tolerance: float,
1135
+ ) -> None:
1136
+ for index, row in enumerate(features):
1137
+ for name, value in zip(R2AG_FEATURE_NAMES, row, strict=True):
1138
+ if value < -1.0 - tolerance or value > 1.0 + tolerance:
1139
+ raise AlgorithmOutputError(
1140
+ f"R²AG feature {index}.{name} is outside cosine range [-1, 1]"
1141
+ )
1142
+ if require_rerank_order and any(
1143
+ features[index][0] + tolerance < features[index + 1][0]
1144
+ for index in range(len(features) - 1)
1145
+ ):
1146
+ raise AlgorithmOutputError(
1147
+ "R²AG fixed candidates must already be ordered by descending rerank score"
1148
+ )
1149
+
1150
+
1151
+ def _require_same_features(
1152
+ expected: Sequence[FeatureRow],
1153
+ returned: Sequence[FeatureRow],
1154
+ *,
1155
+ tolerance: float,
1156
+ ) -> None:
1157
+ for row_index, (left, right) in enumerate(zip(expected, returned, strict=True)):
1158
+ for column_index, (expected_value, returned_value) in enumerate(
1159
+ zip(left, right, strict=True)
1160
+ ):
1161
+ if not math.isclose(
1162
+ expected_value,
1163
+ returned_value,
1164
+ rel_tol=tolerance,
1165
+ abs_tol=tolerance,
1166
+ ):
1167
+ name = R2AG_FEATURE_NAMES[column_index]
1168
+ raise AlgorithmOutputError(f"R²AG worker changed feature {row_index}.{name}")
1169
+
1170
+
1171
+ def _require_echo_hash(payload: Mapping[str, Any], key: str, expected: str) -> None:
1172
+ if required_text(payload, key, label="R²AG response") != expected:
1173
+ raise AlgorithmOutputError(f"R²AG {key} mismatch")
1174
+
1175
+
1176
+ def _sha256_response(payload: Mapping[str, Any], key: str) -> str:
1177
+ value = required_text(payload, key, label="R²AG response")
1178
+ if not _HEX64.fullmatch(value):
1179
+ raise AlgorithmOutputError(f"R²AG response {key} must be a SHA-256 digest")
1180
+ return value
1181
+
1182
+
1183
+ def _validate_runtime_attestation(
1184
+ value: object,
1185
+ *,
1186
+ artifacts: R2AGArtifactIdentity,
1187
+ expected_num_k: int,
1188
+ allow_fixture: bool,
1189
+ ) -> tuple[bool, str]:
1190
+ if not isinstance(value, Mapping):
1191
+ raise AlgorithmOutputError("R²AG response requires runtime_attestation")
1192
+ fixture_mode = value.get("fixture_mode")
1193
+ if not isinstance(fixture_mode, bool):
1194
+ raise AlgorithmOutputError("R²AG runtime attestation fixture_mode must be boolean")
1195
+ if fixture_mode and not allow_fixture:
1196
+ raise AlgorithmOutputError("R²AG production host rejects fixture workers by default")
1197
+ expected: Mapping[str, object] = {
1198
+ "source_commit": R2AG_UPSTREAM_COMMIT,
1199
+ "source_manifest_sha256": artifacts.source_manifest_sha256,
1200
+ "compatibility_manifest_sha256": artifacts.compatibility_manifest_sha256,
1201
+ "checkpoint_config_sha256": artifacts.checkpoint_config_sha256,
1202
+ "rformer_weights_sha256": artifacts.rformer_weights_sha256,
1203
+ "projection_weights_sha256": artifacts.projection_weights_sha256,
1204
+ "base_model_manifest_sha256": artifacts.base_model_manifest_sha256,
1205
+ "tokenizer_manifest_sha256": artifacts.tokenizer_manifest_sha256,
1206
+ "feature_schema_sha256": artifacts.feature_schema_sha256,
1207
+ "worker_config_num_k": expected_num_k,
1208
+ "source_commit_verified": True,
1209
+ "source_files_verified": True,
1210
+ "source_checkout_clean": True,
1211
+ "checkpoint_hashes_verified": True,
1212
+ "rformer_called": True,
1213
+ "projection_called": True,
1214
+ "marker_replacement_called": True,
1215
+ "reader_generate_called": True,
1216
+ "only_marker_positions_modified": True,
1217
+ "gold_metadata_received": False,
1218
+ "training_called": False,
1219
+ "budget_checked_before_reader_call": True,
1220
+ "runtime_dependencies": _RUNTIME_DEPENDENCIES,
1221
+ "runtime_dependencies_verified": not fixture_mode,
1222
+ }
1223
+ for key, expected_value in expected.items():
1224
+ if value.get(key) != expected_value:
1225
+ raise AlgorithmOutputError(f"R²AG runtime attestation mismatch for {key}")
1226
+ evidence_level = value.get("execution_evidence")
1227
+ expected_level = (
1228
+ "fixture_source_execution" if fixture_mode else "pinned_source_checkpoint_execution"
1229
+ )
1230
+ if evidence_level != expected_level:
1231
+ raise AlgorithmOutputError("R²AG runtime execution evidence does not match fixture mode")
1232
+ return fixture_mode, expected_level
1233
+
1234
+
1235
+ def _validate_usage(
1236
+ usage: Any,
1237
+ *,
1238
+ remaining_budget: Mapping[str, int | None],
1239
+ controls: R2AGControls,
1240
+ ) -> None:
1241
+ if usage.model_calls != 1:
1242
+ raise AlgorithmOutputError("R²AG worker must account for exactly one reader model call")
1243
+ if usage.retrieval_calls != 0 or usage.tool_calls != 0:
1244
+ raise AlgorithmOutputError("R²AG worker must not perform retrieval or tool calls")
1245
+ expected_worker_embedding_calls = (
1246
+ 1 if controls.feature_source is R2AGFeatureSource.WORKER else 0
1247
+ )
1248
+ if usage.embedding_calls != expected_worker_embedding_calls:
1249
+ raise AlgorithmOutputError(
1250
+ "R²AG worker embedding-call accounting disagrees with feature_source"
1251
+ )
1252
+ if usage.model_calls > remaining_budget["model_calls"]:
1253
+ raise AlgorithmOutputError("R²AG worker exceeded sent model-call budget")
1254
+ if usage.output_tokens > min(
1255
+ controls.max_output_tokens,
1256
+ remaining_budget["output_tokens"],
1257
+ ):
1258
+ raise AlgorithmOutputError("R²AG worker exceeded sent output-token budget")
1259
+ context_limit = remaining_budget["context_tokens"]
1260
+ if context_limit is not None and usage.input_tokens > context_limit:
1261
+ raise AlgorithmOutputError("R²AG worker exceeded sent context-token budget")
1262
+
1263
+
1264
+ def _remaining_budget(
1265
+ state: FrozenAgentState,
1266
+ context: InterventionContext,
1267
+ ) -> Mapping[str, int | None]:
1268
+ usage = None
1269
+ ledger = context.budget_ledger
1270
+ if ledger is not None:
1271
+ ledger_budget = getattr(ledger, "budget", None)
1272
+ usage = getattr(ledger, "usage", None)
1273
+ if ledger_budget != state.budget or usage is None:
1274
+ raise ValidationError("R²AG received an incompatible budget ledger")
1275
+
1276
+ def consumed(name: str) -> int:
1277
+ value = 0 if usage is None else getattr(usage, name, None)
1278
+ if isinstance(value, bool) or not isinstance(value, int) or value < 0:
1279
+ raise ValidationError(f"R²AG budget usage {name} is invalid")
1280
+ return value
1281
+
1282
+ remaining_context = None
1283
+ if state.budget.max_context_tokens is not None:
1284
+ remaining_context = max(
1285
+ 0,
1286
+ state.budget.max_context_tokens - consumed("input_tokens"),
1287
+ )
1288
+ return freeze_mapping(
1289
+ {
1290
+ "model_calls": max(
1291
+ 0,
1292
+ state.budget.max_model_calls - consumed("model_calls"),
1293
+ ),
1294
+ "output_tokens": max(
1295
+ 0,
1296
+ state.budget.max_output_tokens - consumed("output_tokens"),
1297
+ ),
1298
+ "context_tokens": remaining_context,
1299
+ }
1300
+ )
1301
+
1302
+
1303
+ __all__ = [
1304
+ "R2AG_FEATURE_NAMES",
1305
+ "R2AG_PROTOCOL",
1306
+ "R2AG_UPSTREAM_COMMIT",
1307
+ "R2AGArtifactIdentity",
1308
+ "R2AGControlledWorker",
1309
+ "R2AGControls",
1310
+ "R2AGFeatureSource",
1311
+ "compute_r2ag_retrieval_features",
1312
+ ]