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,248 @@
1
+ """Pre- and post-run dependency balance auditing."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from collections.abc import Mapping
7
+ from dataclasses import dataclass
8
+ from typing import Any
9
+
10
+ from agentinputlab.contracts.dependency import DependencyBinding
11
+ from agentinputlab.contracts.enums import ProfileKind
12
+ from agentinputlab.contracts.errors import BalanceError, ValidationError
13
+ from agentinputlab.contracts.lifecycle import InterventionContext
14
+ from agentinputlab.contracts.serialization import content_hash, freeze_mapping
15
+
16
+ _RUNTIME_COMPONENT_SLOTS = (
17
+ "backend",
18
+ "dense_embedder",
19
+ "retriever",
20
+ "vector_searcher",
21
+ "tools",
22
+ "external_runtime",
23
+ "artifact_manager",
24
+ )
25
+ _HASH_PATTERN = re.compile(r"[0-9a-f]{64}")
26
+ _RESERVED_FINGERPRINT_SLOTS = frozenset(
27
+ (
28
+ *_RUNTIME_COMPONENT_SLOTS,
29
+ "seed",
30
+ "pricing_catalog",
31
+ "intent_contract",
32
+ "strict_intent",
33
+ "run_config",
34
+ )
35
+ )
36
+
37
+
38
+ @dataclass(frozen=True, slots=True)
39
+ class ComparisonProfile:
40
+ profile_id: str
41
+ kind: ProfileKind
42
+ required_slots: tuple[str, ...]
43
+ varied_slots: tuple[str, ...] = ()
44
+ seed_policy: str = "fixed"
45
+ cache_policy: str = "frozen"
46
+
47
+ def __post_init__(self) -> None:
48
+ if set(self.required_slots) & set(self.varied_slots):
49
+ raise ValidationError("a slot cannot be both required-common and varied")
50
+
51
+
52
+ @dataclass(frozen=True, slots=True)
53
+ class ComparisonArm:
54
+ arm_id: str
55
+ release_id: str
56
+ bindings: tuple[DependencyBinding, ...]
57
+
58
+ def binding_map(self) -> dict[str, DependencyBinding]:
59
+ mapping = {binding.slot: binding for binding in self.bindings}
60
+ if len(mapping) != len(self.bindings):
61
+ raise ValidationError(f"arm {self.arm_id} contains duplicate dependency slots")
62
+ return mapping
63
+
64
+
65
+ @dataclass(frozen=True, slots=True)
66
+ class BalanceReport:
67
+ eligible: bool
68
+ differences: tuple[str, ...]
69
+ missing: tuple[str, ...]
70
+
71
+ def require_eligible(self) -> None:
72
+ if not self.eligible:
73
+ details = "; ".join((*self.missing, *self.differences))
74
+ raise BalanceError(f"comparison is not balanced: {details}")
75
+
76
+
77
+ class BalanceAuditor:
78
+ """Compare resolved dependency hashes, never human-readable aliases."""
79
+
80
+ def audit(
81
+ self,
82
+ profile: ComparisonProfile,
83
+ arms: tuple[ComparisonArm, ...],
84
+ *,
85
+ runtime_fingerprints: Mapping[str, Mapping[str, str]] | None = None,
86
+ ) -> BalanceReport:
87
+ if len(arms) < 2:
88
+ raise ValidationError("balance audit requires at least two arms")
89
+ if len({arm.arm_id for arm in arms}) != len(arms):
90
+ raise ValidationError("balance audit requires unique arm IDs")
91
+ maps = {arm.arm_id: arm.binding_map() for arm in arms}
92
+ missing: list[str] = []
93
+ differences: list[str] = []
94
+
95
+ for slot in profile.required_slots:
96
+ absent = [arm.arm_id for arm in arms if slot not in maps[arm.arm_id]]
97
+ if absent:
98
+ missing.append(f"{slot} missing in {','.join(absent)}")
99
+ continue
100
+ hashes = {maps[arm.arm_id][slot].resolved_hash for arm in arms}
101
+ if len(hashes) != 1:
102
+ differences.append(f"{slot} differs across arms")
103
+
104
+ for slot in profile.varied_slots:
105
+ absent = [arm.arm_id for arm in arms if slot not in maps[arm.arm_id]]
106
+ if absent:
107
+ missing.append(f"{slot} missing in {','.join(absent)}")
108
+
109
+ all_slots = set().union(*(set(mapping) for mapping in maps.values()))
110
+ undeclared = all_slots - set(profile.required_slots) - set(profile.varied_slots)
111
+ for slot in sorted(undeclared):
112
+ present = [maps[arm.arm_id].get(slot) for arm in arms]
113
+ if None in present:
114
+ differences.append(f"{slot} is an undeclared asymmetric dependency")
115
+ continue
116
+ hashes = {binding.resolved_hash for binding in present if binding is not None}
117
+ if len(hashes) > 1:
118
+ differences.append(f"{slot} varies but is not declared crossed")
119
+
120
+ if runtime_fingerprints is not None:
121
+ arm_ids = {arm.arm_id for arm in arms}
122
+ if set(runtime_fingerprints) != arm_ids:
123
+ raise ValidationError("runtime fingerprints must be present for every arm")
124
+ for arm_id, fingerprints in runtime_fingerprints.items():
125
+ if not isinstance(fingerprints, Mapping):
126
+ raise ValidationError(f"runtime fingerprints for {arm_id} must be a mapping")
127
+ for slot, fingerprint in fingerprints.items():
128
+ if not isinstance(slot, str) or not slot:
129
+ raise ValidationError("runtime fingerprint slots must be non-empty strings")
130
+ if not isinstance(fingerprint, str) or not _HASH_PATTERN.fullmatch(fingerprint):
131
+ raise ValidationError(
132
+ f"runtime fingerprint {arm_id}.{slot} must be a SHA-256 hex string"
133
+ )
134
+ observed_slots = set().union(*(set(runtime_fingerprints[arm_id]) for arm_id in arm_ids))
135
+ for slot in profile.required_slots:
136
+ if slot not in _RUNTIME_COMPONENT_SLOTS and slot not in observed_slots:
137
+ continue
138
+ absent = [
139
+ arm.arm_id for arm in arms if slot not in runtime_fingerprints[arm.arm_id]
140
+ ]
141
+ if absent:
142
+ _append_unique(missing, f"{slot} runtime missing in {','.join(absent)}")
143
+ continue
144
+ hashes = {runtime_fingerprints[arm.arm_id][slot] for arm in arms}
145
+ if len(hashes) != 1:
146
+ _append_unique(differences, f"{slot} runtime differs across arms")
147
+
148
+ for slot in profile.varied_slots:
149
+ if slot not in _RUNTIME_COMPONENT_SLOTS and slot not in observed_slots:
150
+ continue
151
+ absent = [
152
+ arm.arm_id for arm in arms if slot not in runtime_fingerprints[arm.arm_id]
153
+ ]
154
+ if absent:
155
+ _append_unique(missing, f"{slot} runtime missing in {','.join(absent)}")
156
+
157
+ for slot in sorted(observed_slots):
158
+ present = [runtime_fingerprints[arm.arm_id].get(slot) for arm in arms]
159
+ if slot == "seed":
160
+ if profile.seed_policy == "fixed" and len(set(present)) != 1:
161
+ _append_unique(differences, "seed runtime differs across arms")
162
+ continue
163
+ if slot in profile.required_slots or slot in profile.varied_slots:
164
+ continue
165
+ if None in present:
166
+ _append_unique(
167
+ differences,
168
+ f"{slot} is an undeclared asymmetric runtime dependency",
169
+ )
170
+ elif len(set(present)) > 1:
171
+ _append_unique(
172
+ differences,
173
+ f"{slot} runtime varies but is not declared crossed",
174
+ )
175
+
176
+ return BalanceReport(
177
+ eligible=not missing and not differences,
178
+ differences=tuple(differences),
179
+ missing=tuple(missing),
180
+ )
181
+
182
+
183
+ def context_dependency_fingerprints(context: InterventionContext) -> dict[str, str]:
184
+ """Derive hashes from the objects that will actually execute an arm."""
185
+
186
+ observed: dict[str, str] = {"seed": content_hash(context.seed)}
187
+ for slot in _RUNTIME_COMPONENT_SLOTS:
188
+ dependency = getattr(context, slot)
189
+ if dependency is None:
190
+ continue
191
+ fingerprint = getattr(dependency, "fingerprint", None)
192
+ if not callable(fingerprint):
193
+ raise ValidationError(f"runtime {slot} does not expose fingerprint()")
194
+ identity = fingerprint()
195
+ if not isinstance(identity, Mapping) or not identity:
196
+ raise ValidationError(f"runtime {slot} fingerprint must be a non-empty mapping")
197
+ observed[slot] = _canonical_fingerprint_hash(identity, label=f"runtime {slot} fingerprint")
198
+
199
+ if context.pricing_catalog is not None:
200
+ observed["pricing_catalog"] = content_hash(context.pricing_catalog)
201
+ if context.intent_contract is not None:
202
+ observed["intent_contract"] = content_hash(context.intent_contract)
203
+ observed["strict_intent"] = content_hash(context.strict_intent)
204
+
205
+ declared = context.run_config.get("dependency_fingerprints", {})
206
+ if not isinstance(declared, Mapping):
207
+ raise ValidationError("dependency_fingerprints must be a mapping")
208
+ for slot, identity in declared.items():
209
+ if slot in _RESERVED_FINGERPRINT_SLOTS:
210
+ raise ValidationError(
211
+ f"reserved dependency slot must come from its actual context field: {slot}"
212
+ )
213
+ if slot in observed:
214
+ raise ValidationError(f"runtime dependency slot is reserved or duplicated: {slot}")
215
+ if not isinstance(slot, str) or not slot:
216
+ raise ValidationError("declared dependency slots must be non-empty strings")
217
+ if not isinstance(identity, Mapping) or not identity:
218
+ raise ValidationError(
219
+ f"declared dependency identity for {slot} must be a non-empty mapping"
220
+ )
221
+ observed[slot] = _canonical_fingerprint_hash(
222
+ identity,
223
+ label=f"declared dependency identity for {slot}",
224
+ )
225
+
226
+ remaining_config: dict[str, Any] = {
227
+ key: value for key, value in context.run_config.items() if key != "dependency_fingerprints"
228
+ }
229
+ if remaining_config:
230
+ observed["run_config"] = content_hash(remaining_config)
231
+ return observed
232
+
233
+
234
+ def _append_unique(values: list[str], message: str) -> None:
235
+ if message not in values:
236
+ values.append(message)
237
+
238
+
239
+ def _canonical_fingerprint_hash(identity: Mapping[str, Any], *, label: str) -> str:
240
+ try:
241
+ normalized = freeze_mapping(identity)
242
+ if not normalized:
243
+ raise ValidationError(f"{label} must be a non-empty mapping")
244
+ return content_hash(normalized)
245
+ except ValidationError:
246
+ raise
247
+ except (TypeError, ValueError) as exc:
248
+ raise ValidationError(f"{label} must be canonically serializable: {exc}") from exc
@@ -0,0 +1,135 @@
1
+ """Run cache identities include every declared scientific dependency."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from collections.abc import Mapping
7
+ from typing import Any
8
+
9
+ from agentinputlab.contracts.errors import ValidationError
10
+ from agentinputlab.contracts.serialization import content_hash, freeze_mapping
11
+ from agentinputlab.contracts.state import FrozenAgentState
12
+
13
+ _HASH_PATTERN = re.compile(r"[0-9a-f]{64}")
14
+
15
+
16
+ def run_cache_key(
17
+ *,
18
+ state: FrozenAgentState,
19
+ release_id: str,
20
+ profile_id: str,
21
+ seed: int,
22
+ dependency_hashes: Mapping[str, str] | None = None,
23
+ backend_fingerprint: Mapping[str, Any] | None = None,
24
+ retriever_fingerprint: Mapping[str, Any] | None = None,
25
+ prompt_hash: str = "",
26
+ extra: Mapping[str, Any] | None = None,
27
+ ) -> str:
28
+ """Return a v2 cache identity over all declared execution dependencies.
29
+
30
+ ``dependency_hashes`` accepts the output of
31
+ :func:`context_dependency_fingerprints` directly. The legacy backend and
32
+ retriever fingerprint mappings remain supported during the alpha API, but
33
+ a slot may not be supplied through both interfaces.
34
+ """
35
+
36
+ if isinstance(seed, bool) or not isinstance(seed, int) or seed < 0:
37
+ raise ValidationError("cache seed must be a non-negative integer")
38
+
39
+ normalized = _normalize_dependency_hashes(dependency_hashes, seed=seed)
40
+ for slot, fingerprint in (
41
+ ("backend", backend_fingerprint),
42
+ ("retriever", retriever_fingerprint),
43
+ ):
44
+ if fingerprint is None:
45
+ continue
46
+ if slot in normalized:
47
+ raise ValidationError(
48
+ f"dependency slot supplied through both dependency_hashes and legacy API: {slot}"
49
+ )
50
+ if not isinstance(fingerprint, Mapping):
51
+ raise ValidationError(f"legacy {slot} fingerprint must be a mapping")
52
+ normalized[slot] = _canonical_mapping_hash(
53
+ fingerprint,
54
+ label=f"legacy {slot} fingerprint",
55
+ require_non_empty=True,
56
+ )
57
+
58
+ normalized_extra = _normalize_extra(extra)
59
+
60
+ return content_hash(
61
+ {
62
+ "schema": "agentinputlab-run-cache-v2",
63
+ "state_hash": state.state_hash,
64
+ "release_id": release_id,
65
+ "profile_id": profile_id,
66
+ "dependency_hashes": dict(sorted(normalized.items())),
67
+ "seed": seed,
68
+ "prompt_hash": prompt_hash,
69
+ "extra": dict(normalized_extra),
70
+ }
71
+ )
72
+
73
+
74
+ def _normalize_dependency_hashes(
75
+ dependency_hashes: Mapping[str, str] | None,
76
+ *,
77
+ seed: int,
78
+ ) -> dict[str, str]:
79
+ if dependency_hashes is None:
80
+ return {}
81
+ if not isinstance(dependency_hashes, Mapping):
82
+ raise ValidationError("dependency_hashes must be a mapping")
83
+
84
+ normalized: dict[str, str] = {}
85
+ for slot, fingerprint in dependency_hashes.items():
86
+ if not isinstance(slot, str) or not slot or slot != slot.strip():
87
+ raise ValidationError(
88
+ "dependency hash slots must be non-empty strings without surrounding whitespace"
89
+ )
90
+ if slot in normalized:
91
+ raise ValidationError(f"duplicate dependency hash slot: {slot}")
92
+ if not isinstance(fingerprint, str) or not _HASH_PATTERN.fullmatch(fingerprint):
93
+ raise ValidationError(f"dependency hash {slot} must be a SHA-256 hex string")
94
+ normalized[slot] = fingerprint
95
+
96
+ # The context helper treats seed like any other runtime dependency, while
97
+ # the cache schema stores its value explicitly. Accept the derived hash as
98
+ # a consistency assertion, then remove it so omission cannot create a
99
+ # second key for the same seed.
100
+ supplied_seed_hash = normalized.pop("seed", None)
101
+ if supplied_seed_hash is not None and supplied_seed_hash != content_hash(seed):
102
+ raise ValidationError("dependency seed hash does not match the explicit cache seed")
103
+ return normalized
104
+
105
+
106
+ def _normalize_extra(extra: Mapping[str, Any] | None) -> Mapping[str, Any]:
107
+ if extra is None:
108
+ return freeze_mapping(None)
109
+ if not isinstance(extra, Mapping):
110
+ raise ValidationError("cache extra must be a mapping or None")
111
+ try:
112
+ normalized = freeze_mapping(extra)
113
+ # ``deep_freeze_jsonable`` rejects unsupported values, while canonical
114
+ # serialization additionally rejects non-finite floats.
115
+ content_hash(normalized)
116
+ except (TypeError, ValueError) as exc:
117
+ raise ValidationError(f"cache extra must be canonically serializable: {exc}") from exc
118
+ return normalized
119
+
120
+
121
+ def _canonical_mapping_hash(
122
+ value: Mapping[str, Any],
123
+ *,
124
+ label: str,
125
+ require_non_empty: bool,
126
+ ) -> str:
127
+ try:
128
+ normalized = freeze_mapping(value)
129
+ if require_non_empty and not normalized:
130
+ raise ValidationError(f"{label} must be a non-empty mapping")
131
+ return content_hash(normalized)
132
+ except ValidationError:
133
+ raise
134
+ except (TypeError, ValueError) as exc:
135
+ raise ValidationError(f"{label} must be canonically serializable: {exc}") from exc
@@ -0,0 +1,130 @@
1
+ """Observed runner for full agent/search architectures."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+
7
+ from agentinputlab.contracts import (
8
+ AlgorithmOutputError,
9
+ BudgetExceededError,
10
+ CompositeIntervention,
11
+ CompositeResult,
12
+ FrozenAgentState,
13
+ InterventionContext,
14
+ )
15
+ from agentinputlab.observability import (
16
+ BudgetLedger,
17
+ EventKind,
18
+ ObservedRunStatus,
19
+ PricingCatalog,
20
+ ResourceUsage,
21
+ RunMonitor,
22
+ instrument_context,
23
+ )
24
+
25
+ from .engine import InterventionRunner, _reject_hidden_runtime_dependencies
26
+
27
+
28
+ @dataclass(frozen=True, slots=True)
29
+ class CompositeRunRecord:
30
+ """Observed terminal record for a composite architecture."""
31
+
32
+ release_id: str
33
+ input_state_hash: str
34
+ result: CompositeResult
35
+ monitor_run_id: str = ""
36
+ duration_ms: float | None = None
37
+ usage: ResourceUsage = field(default_factory=ResourceUsage)
38
+
39
+
40
+ class CompositeInterventionRunner:
41
+ """Run a composite profile with the same accounting guarantees as patches."""
42
+
43
+ def __init__(self, *, monitor: RunMonitor | None = None) -> None:
44
+ self.monitor = monitor or RunMonitor()
45
+
46
+ def run(
47
+ self,
48
+ intervention: CompositeIntervention,
49
+ state: FrozenAgentState,
50
+ context: InterventionContext,
51
+ ) -> CompositeRunRecord:
52
+ _reject_hidden_runtime_dependencies(intervention)
53
+ monitor = context.monitor or self.monitor
54
+ if not isinstance(monitor, RunMonitor):
55
+ raise TypeError("context.monitor must be a RunMonitor")
56
+ with monitor.run_scope(
57
+ release_id=intervention.release_id,
58
+ state_hash=state.state_hash,
59
+ tags={
60
+ "method_id": intervention.method_id,
61
+ "family": intervention.family.value,
62
+ "execution_kind": "composite",
63
+ },
64
+ ) as run_id:
65
+ pricing = context.pricing_catalog
66
+ if pricing is not None and not isinstance(pricing, PricingCatalog):
67
+ raise TypeError("context.pricing_catalog must be a PricingCatalog")
68
+ runtime_context = instrument_context(
69
+ context,
70
+ state,
71
+ monitor,
72
+ run_id=run_id,
73
+ pricing=pricing,
74
+ )
75
+ ledger = runtime_context.budget_ledger
76
+ if not isinstance(ledger, BudgetLedger): # pragma: no cover - helper invariant
77
+ raise TypeError("instrumented context did not produce a BudgetLedger")
78
+ monitor.emit(EventKind.STAGE_STARTED, component="composite_intervention")
79
+ try:
80
+ result = intervention.run(state, runtime_context)
81
+ self._validate_result(intervention, state, result)
82
+ InterventionRunner._reconcile_trace_usage(result, ledger, monitor)
83
+ ledger.require_within_budget()
84
+ except BudgetExceededError as exc:
85
+ monitor.record_failure(
86
+ exc,
87
+ category="budget_exhausted",
88
+ stage="composite_intervention",
89
+ )
90
+ monitor.finish_run(ObservedRunStatus.BUDGET_EXHAUSTED, run_id=run_id)
91
+ raise
92
+
93
+ monitor.emit(
94
+ EventKind.STAGE_FINISHED,
95
+ component="composite_intervention",
96
+ payload={"status": "success", "result_hash": result.result_hash},
97
+ )
98
+ snapshot = monitor.finish_run(
99
+ ObservedRunStatus.SUCCEEDED,
100
+ run_id=run_id,
101
+ payload={"outcome": "success"},
102
+ )
103
+ return CompositeRunRecord(
104
+ release_id=intervention.release_id,
105
+ input_state_hash=state.state_hash,
106
+ result=result,
107
+ monitor_run_id=run_id,
108
+ duration_ms=snapshot.duration_ms,
109
+ usage=snapshot.usage,
110
+ )
111
+
112
+ @staticmethod
113
+ def _validate_result(
114
+ intervention: CompositeIntervention,
115
+ state: FrozenAgentState,
116
+ result: object,
117
+ ) -> None:
118
+ if not isinstance(result, CompositeResult):
119
+ raise AlgorithmOutputError(
120
+ f"composite intervention must return a CompositeResult; got {type(result).__name__}"
121
+ )
122
+ if result.method_id != intervention.method_id:
123
+ raise AlgorithmOutputError("composite returned a result for another method")
124
+ if result.release_id != intervention.release_id:
125
+ raise AlgorithmOutputError("composite returned a result for another release")
126
+ if result.source_state_hash != state.state_hash:
127
+ raise AlgorithmOutputError("composite result source_state_hash mismatch")
128
+
129
+
130
+ __all__ = ["CompositeInterventionRunner", "CompositeRunRecord"]