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,613 @@
1
+ """Dependency-free HTTP server for the packaged local AgentInputLab Studio."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import mimetypes
8
+ import os
9
+ import re
10
+ import socket
11
+ import sys
12
+ from http import HTTPStatus
13
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
14
+ from pathlib import Path
15
+ from typing import Any
16
+ from urllib.parse import urlsplit
17
+
18
+ from agentinputlab.contracts.errors import ArtifactError, ValidationError
19
+
20
+ from .campaigns import (
21
+ CampaignManager,
22
+ CampaignQueueFullError,
23
+ CampaignSecurityError,
24
+ CampaignValidationError,
25
+ disabled_campaign_catalog_payload,
26
+ )
27
+ from .engine import (
28
+ RunManager,
29
+ StudioQueueFullError,
30
+ StudioSecurityError,
31
+ StudioValidationError,
32
+ validate_config,
33
+ )
34
+ from .model_backends import (
35
+ STUDIO_MODEL_BACKEND_CONFIG_ENV,
36
+ STUDIO_MODEL_BACKEND_CONFIG_SHA256_ENV,
37
+ StudioModelBackendGate,
38
+ )
39
+
40
+ MAX_REQUEST_BYTES = 65_536
41
+ LOOPBACK_HOSTS = frozenset({"127.0.0.1", "localhost", "::1"})
42
+ RUN_ID = re.compile(r"^[0-9a-f]{32}$")
43
+ STATIC_DIR = Path(__file__).resolve().parent / "static"
44
+ STATIC_ROUTES = {
45
+ "/": "index.html",
46
+ "/index.html": "index.html",
47
+ "/result": "result.html",
48
+ "/result.html": "result.html",
49
+ "/campaigns": "campaigns.html",
50
+ "/campaigns.html": "campaigns.html",
51
+ "/styles.css": "styles.css",
52
+ "/app.js": "app.js",
53
+ "/result.js": "result.js",
54
+ "/campaigns.js": "campaigns.js",
55
+ }
56
+
57
+
58
+ class StudioHTTPServer(ThreadingHTTPServer):
59
+ daemon_threads = True
60
+ allow_reuse_address = True
61
+
62
+ def __init__(
63
+ self,
64
+ server_address: tuple[str, int],
65
+ handler: type[BaseHTTPRequestHandler],
66
+ *,
67
+ manager: RunManager,
68
+ campaign_manager: CampaignManager | None = None,
69
+ ) -> None:
70
+ self.manager = manager
71
+ self.catalog = manager.catalog
72
+ self.campaign_manager = campaign_manager
73
+ self.address_family = socket.AF_INET6 if ":" in server_address[0] else socket.AF_INET
74
+ super().__init__(server_address, handler)
75
+
76
+ def server_close(self) -> None:
77
+ try:
78
+ super().server_close()
79
+ finally:
80
+ self.manager.shutdown(wait=True)
81
+ if self.campaign_manager is not None:
82
+ self.campaign_manager.shutdown(wait=True)
83
+
84
+
85
+ class StudioHandler(BaseHTTPRequestHandler):
86
+ server: StudioHTTPServer
87
+ protocol_version = "HTTP/1.1"
88
+
89
+ def _accept_host(self) -> bool:
90
+ raw_host = self.headers.get("Host", "")
91
+ try:
92
+ parsed = urlsplit(f"//{raw_host}")
93
+ _ = parsed.port
94
+ except ValueError:
95
+ parsed = None
96
+ if (
97
+ parsed is None
98
+ or parsed.hostname not in LOOPBACK_HOSTS
99
+ or parsed.username is not None
100
+ or parsed.password is not None
101
+ ):
102
+ self._send_error(
103
+ HTTPStatus.MISDIRECTED_REQUEST,
104
+ "host_rejected",
105
+ "Host must be localhost, 127.0.0.1, or [::1]",
106
+ )
107
+ return False
108
+ return True
109
+
110
+ def _security_headers(self) -> None:
111
+ self.send_header("X-Content-Type-Options", "nosniff")
112
+ self.send_header("X-Frame-Options", "DENY")
113
+ self.send_header("Referrer-Policy", "no-referrer")
114
+ self.send_header(
115
+ "Content-Security-Policy",
116
+ "default-src 'self'; script-src 'self'; style-src 'self'; "
117
+ "img-src 'self' data:; connect-src 'self'; object-src 'none'; "
118
+ "base-uri 'none'; frame-ancestors 'none'; form-action 'self'",
119
+ )
120
+ self.send_header(
121
+ "Permissions-Policy",
122
+ "camera=(), microphone=(), geolocation=(), payment=(), usb=()",
123
+ )
124
+
125
+ def _send_json(
126
+ self,
127
+ payload: Any,
128
+ *,
129
+ status: HTTPStatus = HTTPStatus.OK,
130
+ ) -> None:
131
+ data = json.dumps(
132
+ payload,
133
+ ensure_ascii=False,
134
+ sort_keys=True,
135
+ separators=(",", ":"),
136
+ allow_nan=False,
137
+ ).encode("utf-8")
138
+ self.send_response(status)
139
+ self.send_header("Content-Type", "application/json; charset=utf-8")
140
+ self.send_header("Content-Length", str(len(data)))
141
+ self.send_header("Cache-Control", "no-store")
142
+ self._security_headers()
143
+ self.end_headers()
144
+ self.wfile.write(data)
145
+
146
+ def _send_error(self, status: HTTPStatus, code: str, message: str) -> None:
147
+ self._send_json(
148
+ {"error": {"code": code, "message": message}},
149
+ status=status,
150
+ )
151
+
152
+ def _read_json(self) -> Any:
153
+ content_type = self.headers.get("Content-Type", "").partition(";")[0].strip().lower()
154
+ if content_type != "application/json":
155
+ raise _HTTPInputError(
156
+ HTTPStatus.UNSUPPORTED_MEDIA_TYPE,
157
+ "content_type",
158
+ "Content-Type must be application/json",
159
+ )
160
+ raw_length = self.headers.get("Content-Length")
161
+ try:
162
+ length = int(raw_length or "0")
163
+ except ValueError as exc:
164
+ raise _HTTPInputError(
165
+ HTTPStatus.BAD_REQUEST,
166
+ "content_length",
167
+ "invalid Content-Length",
168
+ ) from exc
169
+ if length < 1:
170
+ raise _HTTPInputError(HTTPStatus.BAD_REQUEST, "empty_body", "JSON body is required")
171
+ if length > MAX_REQUEST_BYTES:
172
+ raise _HTTPInputError(
173
+ HTTPStatus.REQUEST_ENTITY_TOO_LARGE,
174
+ "body_too_large",
175
+ f"request exceeds {MAX_REQUEST_BYTES} bytes",
176
+ )
177
+ data = self.rfile.read(length)
178
+ try:
179
+ return json.loads(data.decode("utf-8"))
180
+ except (UnicodeDecodeError, json.JSONDecodeError) as exc:
181
+ raise _HTTPInputError(
182
+ HTTPStatus.BAD_REQUEST,
183
+ "invalid_json",
184
+ "body must be valid UTF-8 JSON",
185
+ ) from exc
186
+
187
+ def do_GET(self) -> None:
188
+ if not self._accept_host():
189
+ return
190
+ parsed = urlsplit(self.path)
191
+ path = parsed.path
192
+ if path == "/api/health":
193
+ self._send_json(
194
+ {
195
+ "ok": True,
196
+ "service": "agentinputlab-studio",
197
+ "version": 1,
198
+ "execution": "local-only",
199
+ "network_runs": bool(
200
+ self.server.catalog["execution_policy"]["network_enabled"]
201
+ ),
202
+ "campaign_mode_configured": self.server.campaign_manager is not None,
203
+ }
204
+ )
205
+ return
206
+ if path == "/api/catalog":
207
+ self._send_json(self.server.catalog)
208
+ return
209
+ if path == "/api/campaigns/profiles":
210
+ campaigns = self.server.campaign_manager
211
+ self._send_json(
212
+ campaigns.catalog_payload()
213
+ if campaigns is not None
214
+ else disabled_campaign_catalog_payload()
215
+ )
216
+ return
217
+ if path == "/api/campaigns/executions":
218
+ campaigns = self.server.campaign_manager
219
+ self._send_json(
220
+ {
221
+ "configured": campaigns is not None,
222
+ "executions": (campaigns.list_executions() if campaigns is not None else []),
223
+ }
224
+ )
225
+ return
226
+ if path.startswith("/api/campaigns/executions/"):
227
+ execution_id = path.removeprefix("/api/campaigns/executions/")
228
+ campaigns = self.server.campaign_manager
229
+ record = (
230
+ campaigns.get_execution(execution_id)
231
+ if campaigns is not None and RUN_ID.fullmatch(execution_id)
232
+ else None
233
+ )
234
+ if record is None:
235
+ self._send_error(
236
+ HTTPStatus.NOT_FOUND,
237
+ "campaign_execution_not_found",
238
+ "campaign execution does not exist",
239
+ )
240
+ return
241
+ self._send_json(record)
242
+ return
243
+ if path.startswith("/api/campaigns/preflights/"):
244
+ preparation_id = path.removeprefix("/api/campaigns/preflights/")
245
+ campaigns = self.server.campaign_manager
246
+ record = (
247
+ campaigns.get_preparation(preparation_id)
248
+ if campaigns is not None and RUN_ID.fullmatch(preparation_id)
249
+ else None
250
+ )
251
+ if record is None:
252
+ self._send_error(
253
+ HTTPStatus.NOT_FOUND,
254
+ "campaign_preflight_not_found",
255
+ "campaign preflight does not exist",
256
+ )
257
+ return
258
+ self._send_json(record)
259
+ return
260
+ if path == "/api/runs":
261
+ self._send_json({"runs": self.server.manager.list_runs()})
262
+ return
263
+ if path.startswith("/api/runs/"):
264
+ run_id = path.removeprefix("/api/runs/")
265
+ if not RUN_ID.fullmatch(run_id):
266
+ self._send_error(HTTPStatus.NOT_FOUND, "run_not_found", "run does not exist")
267
+ return
268
+ record = self.server.manager.get(run_id)
269
+ if record is None:
270
+ self._send_error(HTTPStatus.NOT_FOUND, "run_not_found", "run does not exist")
271
+ return
272
+ self._send_json(record)
273
+ return
274
+ if path in STATIC_ROUTES:
275
+ self._send_static(STATIC_ROUTES[path])
276
+ return
277
+ self._send_error(HTTPStatus.NOT_FOUND, "not_found", "route does not exist")
278
+
279
+ def do_POST(self) -> None:
280
+ if not self._accept_host():
281
+ return
282
+ path = urlsplit(self.path).path
283
+ if path not in {
284
+ "/api/validate",
285
+ "/api/runs",
286
+ "/api/campaigns/preflight",
287
+ "/api/campaigns/executions",
288
+ }:
289
+ self._send_error(HTTPStatus.NOT_FOUND, "not_found", "route does not exist")
290
+ return
291
+ if path.startswith("/api/campaigns/"):
292
+ self._handle_campaign_post(path)
293
+ return
294
+ try:
295
+ payload = self._read_json()
296
+ report = validate_config(payload, catalog=self.server.catalog)
297
+ except _HTTPInputError as exc:
298
+ self._send_error(exc.status, exc.code, exc.message)
299
+ return
300
+ except StudioSecurityError as exc:
301
+ self._send_error(HTTPStatus.FORBIDDEN, "credentials_rejected", str(exc))
302
+ return
303
+ if path == "/api/validate":
304
+ self._send_json(report)
305
+ return
306
+ if not report["valid"]:
307
+ self._send_json(report, status=HTTPStatus.UNPROCESSABLE_ENTITY)
308
+ return
309
+ try:
310
+ run = self.server.manager.submit(payload)
311
+ except StudioQueueFullError as exc:
312
+ self._send_error(HTTPStatus.TOO_MANY_REQUESTS, "queue_full", str(exc))
313
+ return
314
+ except StudioValidationError as exc:
315
+ self._send_error(HTTPStatus.UNPROCESSABLE_ENTITY, "invalid_config", str(exc))
316
+ return
317
+ self._send_json(run, status=HTTPStatus.ACCEPTED)
318
+
319
+ def _handle_campaign_post(self, path: str) -> None:
320
+ campaigns = self.server.campaign_manager
321
+ if campaigns is None:
322
+ self._send_error(
323
+ HTTPStatus.CONFLICT,
324
+ "campaigns_not_configured",
325
+ "Studio was not started with a campaign profile catalog",
326
+ )
327
+ return
328
+ try:
329
+ payload = self._read_json()
330
+ if path == "/api/campaigns/preflight":
331
+ self._send_json(campaigns.prepare(payload))
332
+ return
333
+ self._send_json(
334
+ campaigns.submit_execution(payload),
335
+ status=HTTPStatus.ACCEPTED,
336
+ )
337
+ except _HTTPInputError as exc:
338
+ self._send_error(exc.status, exc.code, exc.message)
339
+ except CampaignSecurityError as exc:
340
+ self._send_error(
341
+ HTTPStatus.FORBIDDEN,
342
+ "campaign_input_rejected",
343
+ str(exc),
344
+ )
345
+ except CampaignQueueFullError as exc:
346
+ self._send_error(HTTPStatus.TOO_MANY_REQUESTS, "queue_full", str(exc))
347
+ except CampaignValidationError as exc:
348
+ self._send_error(
349
+ HTTPStatus.UNPROCESSABLE_ENTITY,
350
+ "campaign_invalid",
351
+ str(exc),
352
+ )
353
+ except (ArtifactError, ValidationError):
354
+ self._send_error(
355
+ HTTPStatus.UNPROCESSABLE_ENTITY,
356
+ "campaign_preflight_failed",
357
+ "Campaign profile attestation or preflight failed",
358
+ )
359
+
360
+ def do_OPTIONS(self) -> None:
361
+ if not self._accept_host():
362
+ return
363
+ self.send_response(HTTPStatus.METHOD_NOT_ALLOWED)
364
+ self.send_header("Allow", "GET, POST")
365
+ self.send_header("Content-Length", "0")
366
+ self._security_headers()
367
+ self.end_headers()
368
+
369
+ def _send_static(self, filename: str) -> None:
370
+ path = STATIC_DIR / filename
371
+ try:
372
+ data = path.read_bytes()
373
+ except OSError:
374
+ self._send_error(HTTPStatus.NOT_FOUND, "asset_not_found", "asset does not exist")
375
+ return
376
+ content_type = mimetypes.guess_type(filename)[0] or "application/octet-stream"
377
+ if content_type.startswith("text/") or content_type == "application/javascript":
378
+ content_type = f"{content_type}; charset=utf-8"
379
+ self.send_response(HTTPStatus.OK)
380
+ self.send_header("Content-Type", content_type)
381
+ self.send_header("Content-Length", str(len(data)))
382
+ self.send_header("Cache-Control", "no-cache")
383
+ self._security_headers()
384
+ self.end_headers()
385
+ self.wfile.write(data)
386
+
387
+ def log_message(self, format: str, *args: Any) -> None:
388
+ # The handler never logs request bodies or headers, which keeps secrets
389
+ # out of terminal output even when a client sends a rejected payload.
390
+ sys.stderr.write(
391
+ f"studio {self.client_address[0]} {self.command} "
392
+ f"{urlsplit(self.path).path} — {format % args}\n"
393
+ )
394
+
395
+
396
+ class _HTTPInputError(Exception):
397
+ def __init__(self, status: HTTPStatus, code: str, message: str) -> None:
398
+ super().__init__(message)
399
+ self.status = status
400
+ self.code = code
401
+ self.message = message
402
+
403
+
404
+ def create_server(
405
+ host: str = "127.0.0.1",
406
+ port: int = 7861,
407
+ *,
408
+ max_workers: int = 1,
409
+ manager: RunManager | None = None,
410
+ prepared_data_root: str | Path | None = None,
411
+ campaign_manager: CampaignManager | None = None,
412
+ campaign_catalog_path: str | Path | None = None,
413
+ campaign_output_root: str | Path | None = None,
414
+ campaign_workers: int = 1,
415
+ model_backend_gate: StudioModelBackendGate | None = None,
416
+ model_backend_config_path: str | Path | None = None,
417
+ model_backend_config_sha256: str | None = None,
418
+ allow_remote: bool = False,
419
+ ) -> StudioHTTPServer:
420
+ if host not in LOOPBACK_HOSTS and not allow_remote:
421
+ raise ValueError(
422
+ "refusing non-loopback bind without allow_remote=True; Studio has no authentication"
423
+ )
424
+ if manager is not None and prepared_data_root is not None:
425
+ raise ValueError("prepared_data_root must be configured on the supplied RunManager")
426
+ if manager is not None and (
427
+ model_backend_gate is not None
428
+ or model_backend_config_path is not None
429
+ or model_backend_config_sha256 is not None
430
+ ):
431
+ raise ValueError("model backend gate must be configured on the supplied RunManager")
432
+ if model_backend_gate is not None and (
433
+ model_backend_config_path is not None or model_backend_config_sha256 is not None
434
+ ):
435
+ raise ValueError("supply either model_backend_gate or operator config path/SHA, not both")
436
+ if campaign_manager is not None and (
437
+ campaign_catalog_path is not None or campaign_output_root is not None
438
+ ):
439
+ raise ValueError(
440
+ "campaign catalog/output must be configured on the supplied CampaignManager"
441
+ )
442
+ if campaign_catalog_path is None and campaign_output_root is not None:
443
+ raise ValueError("campaign_output_root requires campaign_catalog_path")
444
+ operator_backend_gate = model_backend_gate or StudioModelBackendGate.from_operator_config(
445
+ model_backend_config_path,
446
+ model_backend_config_sha256,
447
+ )
448
+ run_manager = manager or RunManager(
449
+ max_workers=max_workers,
450
+ prepared_data_root=prepared_data_root,
451
+ model_backend_gate=operator_backend_gate,
452
+ )
453
+ campaigns = campaign_manager
454
+ owns_campaigns = campaigns is None and campaign_catalog_path is not None
455
+ try:
456
+ if owns_campaigns:
457
+ campaigns = CampaignManager(
458
+ catalog_path=campaign_catalog_path,
459
+ output_root=campaign_output_root,
460
+ max_workers=campaign_workers,
461
+ )
462
+ return StudioHTTPServer(
463
+ (host, port),
464
+ StudioHandler,
465
+ manager=run_manager,
466
+ campaign_manager=campaigns,
467
+ )
468
+ except Exception:
469
+ if manager is None:
470
+ run_manager.shutdown(wait=True)
471
+ if owns_campaigns and campaigns is not None:
472
+ campaigns.shutdown(wait=True)
473
+ raise
474
+
475
+
476
+ def build_parser() -> argparse.ArgumentParser:
477
+ parser = argparse.ArgumentParser(description="Run the local AgentInputLab experiment Studio.")
478
+ parser.add_argument("--host", default="127.0.0.1", help="Bind host (loopback by default).")
479
+ parser.add_argument("--port", type=int, default=7861, help="Bind port.")
480
+ parser.add_argument("--workers", type=int, default=1, choices=range(1, 5))
481
+ parser.add_argument(
482
+ "--prepared-data-root",
483
+ type=Path,
484
+ default=(
485
+ Path(os.environ["AGENTINPUTLAB_PREPARED_DATA_ROOT"])
486
+ if os.environ.get("AGENTINPUTLAB_PREPARED_DATA_ROOT")
487
+ else None
488
+ ),
489
+ help=(
490
+ "Server-controlled prepared benchmark cache root. "
491
+ "May also be set with AGENTINPUTLAB_PREPARED_DATA_ROOT."
492
+ ),
493
+ )
494
+ parser.add_argument(
495
+ "--allow-remote",
496
+ action="store_true",
497
+ help="Acknowledge that remote binding has no authentication and is unsafe on public networks.",
498
+ )
499
+ parser.add_argument(
500
+ "--campaign-catalog",
501
+ type=Path,
502
+ default=(
503
+ Path(os.environ["AGENTINPUTLAB_CAMPAIGN_CATALOG"])
504
+ if os.environ.get("AGENTINPUTLAB_CAMPAIGN_CATALOG")
505
+ else None
506
+ ),
507
+ help=(
508
+ "Server-controlled, checksum-locked campaign profile catalog. "
509
+ "Never accepted from a browser request."
510
+ ),
511
+ )
512
+ parser.add_argument(
513
+ "--campaign-output-root",
514
+ type=Path,
515
+ default=(
516
+ Path(os.environ["AGENTINPUTLAB_CAMPAIGN_OUTPUT_ROOT"])
517
+ if os.environ.get("AGENTINPUTLAB_CAMPAIGN_OUTPUT_ROOT")
518
+ else None
519
+ ),
520
+ help=(
521
+ "Server-controlled campaign artifact root. Without it, campaign "
522
+ "profiles remain preflight/plan only."
523
+ ),
524
+ )
525
+ parser.add_argument(
526
+ "--campaign-workers",
527
+ type=int,
528
+ default=1,
529
+ choices=range(1, 5),
530
+ help="Bounded campaign workers, separate from tiny Studio runs.",
531
+ )
532
+ parser.add_argument(
533
+ "--model-backend-config",
534
+ type=Path,
535
+ default=(
536
+ Path(os.environ[STUDIO_MODEL_BACKEND_CONFIG_ENV])
537
+ if os.environ.get(STUDIO_MODEL_BACKEND_CONFIG_ENV)
538
+ else None
539
+ ),
540
+ help=(
541
+ "Server-controlled ProductionBackendBuilder parameter file. "
542
+ f"May also be set with {STUDIO_MODEL_BACKEND_CONFIG_ENV}; never "
543
+ "accepted from a browser request."
544
+ ),
545
+ )
546
+ parser.add_argument(
547
+ "--model-backend-config-sha256",
548
+ default=os.environ.get(STUDIO_MODEL_BACKEND_CONFIG_SHA256_ENV),
549
+ help=(
550
+ "Exact SHA-256 of --model-backend-config. "
551
+ f"May also be set with {STUDIO_MODEL_BACKEND_CONFIG_SHA256_ENV}."
552
+ ),
553
+ )
554
+ return parser
555
+
556
+
557
+ def main(argv: list[str] | None = None) -> int:
558
+ args = build_parser().parse_args(argv)
559
+ if args.host not in LOOPBACK_HOSTS and not args.allow_remote:
560
+ print(
561
+ "refusing non-loopback bind without --allow-remote; Studio has no authentication",
562
+ file=sys.stderr,
563
+ )
564
+ return 2
565
+ server = create_server(
566
+ args.host,
567
+ args.port,
568
+ max_workers=args.workers,
569
+ prepared_data_root=args.prepared_data_root,
570
+ campaign_catalog_path=args.campaign_catalog,
571
+ campaign_output_root=args.campaign_output_root,
572
+ campaign_workers=args.campaign_workers,
573
+ model_backend_config_path=args.model_backend_config,
574
+ model_backend_config_sha256=args.model_backend_config_sha256,
575
+ allow_remote=args.allow_remote,
576
+ )
577
+ host, port = server.server_address[:2]
578
+ print(f"AgentInputLab Studio listening on http://{host}:{port}")
579
+ model_backend_id = server.catalog["execution_policy"]["operator_model_backend_id"]
580
+ if model_backend_id is None:
581
+ print("Local execution only · credentials rejected · operator model backend locked")
582
+ else:
583
+ print(
584
+ "Local execution only · credentials rejected · "
585
+ f"operator model backend ready: {model_backend_id}"
586
+ )
587
+ verified_cells = server.catalog["execution_policy"]["verified_prepared_cells"]
588
+ if verified_cells:
589
+ print(f"Verified prepared benchmark cells: {', '.join(verified_cells)}")
590
+ if server.campaign_manager is None:
591
+ print("Research campaigns: disabled (no server-side profile catalog)")
592
+ else:
593
+ profiles = server.campaign_manager.catalog_payload()["profiles"]
594
+ mode = (
595
+ "preflight + confirmed execution"
596
+ if args.campaign_output_root is not None
597
+ else "preflight/plan only"
598
+ )
599
+ print(f"Research campaigns: {len(profiles)} allowlisted profiles · {mode}")
600
+ try:
601
+ server.serve_forever(poll_interval=0.25)
602
+ except KeyboardInterrupt:
603
+ print("\nStopping Studio")
604
+ finally:
605
+ server.server_close()
606
+ return 0
607
+
608
+
609
+ if __name__ == "__main__":
610
+ raise SystemExit(main())
611
+
612
+
613
+ __all__ = ["MAX_REQUEST_BYTES", "StudioHTTPServer", "create_server", "main"]