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,157 @@
1
+ """Checksum-verified local artifact store with atomic writes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import os
7
+ import tempfile
8
+ from collections.abc import Iterable
9
+ from dataclasses import dataclass
10
+ from pathlib import Path
11
+
12
+ from agentinputlab.contracts.errors import ArtifactError
13
+
14
+ from .manifest import ArtifactManifest
15
+
16
+
17
+ def sha256_file(path: str | Path, *, chunk_size: int = 1024 * 1024) -> str:
18
+ digest = hashlib.sha256()
19
+ with Path(path).open("rb") as handle:
20
+ while chunk := handle.read(chunk_size):
21
+ digest.update(chunk)
22
+ return digest.hexdigest()
23
+
24
+
25
+ @dataclass(slots=True)
26
+ class ArtifactStore:
27
+ root: Path
28
+
29
+ def __init__(self, root: str | Path) -> None:
30
+ self.root = Path(root).expanduser().resolve()
31
+ self.root.mkdir(parents=True, exist_ok=True)
32
+
33
+ def path_for(self, manifest: ArtifactManifest) -> Path:
34
+ candidate = (self.root / manifest.artifact_id / manifest.revision / "payload").resolve()
35
+ if self.root not in candidate.parents:
36
+ raise ArtifactError("artifact path escaped store root")
37
+ return candidate
38
+
39
+ def verify(self, manifest: ArtifactManifest) -> Path:
40
+ path = self.path_for(manifest)
41
+ if not path.is_file():
42
+ raise ArtifactError(f"artifact missing: {manifest.artifact_id}@{manifest.revision}")
43
+ if manifest.size_bytes is not None and path.stat().st_size != manifest.size_bytes:
44
+ raise ArtifactError(f"artifact size mismatch: {manifest.artifact_id}")
45
+ if manifest.sha256 and sha256_file(path) != manifest.sha256:
46
+ raise ArtifactError(f"artifact checksum mismatch: {manifest.artifact_id}")
47
+ return path
48
+
49
+ def put_bytes(self, manifest: ArtifactManifest, content: bytes) -> Path:
50
+ digest = hashlib.sha256(content).hexdigest()
51
+ if manifest.sha256 and digest != manifest.sha256:
52
+ raise ArtifactError(
53
+ f"refusing materialization: checksum mismatch for {manifest.artifact_id}"
54
+ )
55
+ if manifest.size_bytes is not None and len(content) != manifest.size_bytes:
56
+ raise ArtifactError(
57
+ f"refusing materialization: size mismatch for {manifest.artifact_id}"
58
+ )
59
+ destination = self.path_for(manifest)
60
+ destination.parent.mkdir(parents=True, exist_ok=True)
61
+ if destination.exists():
62
+ if destination.is_file() and destination.read_bytes() == content:
63
+ return self.verify(manifest)
64
+ raise ArtifactError(
65
+ "refusing to overwrite an existing artifact revision with different content: "
66
+ f"{manifest.artifact_id}@{manifest.revision}"
67
+ )
68
+ descriptor, temporary_name = tempfile.mkstemp(
69
+ prefix=".partial-",
70
+ dir=destination.parent,
71
+ )
72
+ try:
73
+ with os.fdopen(descriptor, "wb") as handle:
74
+ handle.write(content)
75
+ handle.flush()
76
+ os.fsync(handle.fileno())
77
+ try:
78
+ # Linking a fully flushed temporary file is atomic and, unlike
79
+ # os.replace(), cannot overwrite a concurrently materialized
80
+ # artifact revision.
81
+ os.link(temporary_name, destination)
82
+ except FileExistsError:
83
+ if not destination.is_file() or destination.read_bytes() != content:
84
+ raise ArtifactError(
85
+ "refusing concurrent overwrite of artifact revision: "
86
+ f"{manifest.artifact_id}@{manifest.revision}"
87
+ ) from None
88
+ finally:
89
+ if os.path.exists(temporary_name):
90
+ os.unlink(temporary_name)
91
+ return self.verify(manifest)
92
+
93
+ def import_file(self, manifest: ArtifactManifest, source: str | Path) -> Path:
94
+ source_path = Path(source).resolve()
95
+ if not source_path.is_file():
96
+ raise ArtifactError(f"source artifact is not a regular file: {source_path}")
97
+ with source_path.open("rb") as handle:
98
+ return self.put_stream(manifest, iter(lambda: handle.read(1024 * 1024), b""))
99
+
100
+ def put_stream(
101
+ self,
102
+ manifest: ArtifactManifest,
103
+ chunks: Iterable[bytes],
104
+ *,
105
+ max_bytes: int | None = None,
106
+ ) -> Path:
107
+ """Hash bounded chunks to a temporary file and publish create-only.
108
+
109
+ A network interruption, size violation, or bad checksum never leaves a
110
+ usable payload. Concurrent downloads cannot replace an existing revision.
111
+ Neither the incoming payload nor an existing payload is buffered in RAM.
112
+ """
113
+ if max_bytes is not None and max_bytes < 0:
114
+ raise ArtifactError("stream size limit must be non-negative")
115
+ destination = self.path_for(manifest)
116
+ destination.parent.mkdir(parents=True, exist_ok=True)
117
+ descriptor, temporary_name = tempfile.mkstemp(prefix=".partial-", dir=destination.parent)
118
+ digest = hashlib.sha256()
119
+ size = 0
120
+ try:
121
+ with os.fdopen(descriptor, "wb") as handle:
122
+ for chunk in chunks:
123
+ if not isinstance(chunk, bytes):
124
+ raise ArtifactError("artifact stream must yield bytes")
125
+ size += len(chunk)
126
+ if (max_bytes is not None and size > max_bytes) or (
127
+ manifest.size_bytes is not None and size > manifest.size_bytes
128
+ ):
129
+ raise ArtifactError("artifact stream exceeds size limit")
130
+ digest.update(chunk)
131
+ handle.write(chunk)
132
+ if manifest.size_bytes is not None and size != manifest.size_bytes:
133
+ raise ArtifactError(
134
+ f"refusing materialization: size mismatch for {manifest.artifact_id}"
135
+ )
136
+ if manifest.sha256 and digest.hexdigest() != manifest.sha256:
137
+ raise ArtifactError(
138
+ f"refusing materialization: checksum mismatch for {manifest.artifact_id}"
139
+ )
140
+ handle.flush()
141
+ os.fsync(handle.fileno())
142
+ try:
143
+ os.link(temporary_name, destination)
144
+ except FileExistsError:
145
+ if (
146
+ not destination.is_file()
147
+ or destination.stat().st_size != size
148
+ or sha256_file(destination) != digest.hexdigest()
149
+ ):
150
+ raise ArtifactError(
151
+ "refusing concurrent overwrite of artifact revision: "
152
+ f"{manifest.artifact_id}@{manifest.revision}"
153
+ ) from None
154
+ finally:
155
+ if os.path.exists(temporary_name):
156
+ os.unlink(temporary_name)
157
+ return destination
@@ -0,0 +1,98 @@
1
+ """Backend contracts for LLMs, retrieval, embedding, and user simulators."""
2
+
3
+ from .embedding import (
4
+ CallableEmbeddingBackend,
5
+ DeterministicHashEmbeddingBackend,
6
+ EmbeddingBackend,
7
+ EmbeddingRequest,
8
+ EmbeddingResponse,
9
+ EmbeddingUsage,
10
+ ReplayEmbeddingBackend,
11
+ )
12
+ from .llm import (
13
+ FINAL_CONTENT_STOP_POLICY_ID,
14
+ CallableBackend,
15
+ DecompCompletionBackend,
16
+ FinalContentStopBackend,
17
+ GenerationRequest,
18
+ GenerationResponse,
19
+ LLMBackend,
20
+ ModelCapability,
21
+ OpenAICompatibleBackend,
22
+ ReplayBackend,
23
+ TransformersBackend,
24
+ Usage,
25
+ require_capabilities,
26
+ )
27
+ from .retrieval import (
28
+ DENSE_RETRIEVER_PROFILE_IDS,
29
+ RETRIEVER_PROFILES,
30
+ BatchTextEncoder,
31
+ DenseIndexSummary,
32
+ Document,
33
+ EmbeddingBackendEncoder,
34
+ FunctionRetriever,
35
+ InMemoryBM25Retriever,
36
+ RetrievalResult,
37
+ Retriever,
38
+ RetrieverProfile,
39
+ SentenceTransformerDenseRetriever,
40
+ SQLiteFTS5Retriever,
41
+ build_retriever,
42
+ retriever_profile,
43
+ )
44
+ from .user import (
45
+ CallableUserResponder,
46
+ ReplayTurn,
47
+ ReplayUserResponder,
48
+ UserRequest,
49
+ UserResponder,
50
+ UserResponse,
51
+ )
52
+ from .vector import DenseEmbedder, VectorSearcher
53
+
54
+ __all__ = [
55
+ "DENSE_RETRIEVER_PROFILE_IDS",
56
+ "FINAL_CONTENT_STOP_POLICY_ID",
57
+ "RETRIEVER_PROFILES",
58
+ "BatchTextEncoder",
59
+ "CallableBackend",
60
+ "CallableEmbeddingBackend",
61
+ "CallableUserResponder",
62
+ "DecompCompletionBackend",
63
+ "DenseEmbedder",
64
+ "DenseIndexSummary",
65
+ "DeterministicHashEmbeddingBackend",
66
+ "Document",
67
+ "EmbeddingBackend",
68
+ "EmbeddingBackendEncoder",
69
+ "EmbeddingRequest",
70
+ "EmbeddingResponse",
71
+ "EmbeddingUsage",
72
+ "FinalContentStopBackend",
73
+ "FunctionRetriever",
74
+ "GenerationRequest",
75
+ "GenerationResponse",
76
+ "InMemoryBM25Retriever",
77
+ "LLMBackend",
78
+ "ModelCapability",
79
+ "OpenAICompatibleBackend",
80
+ "ReplayBackend",
81
+ "ReplayEmbeddingBackend",
82
+ "ReplayTurn",
83
+ "ReplayUserResponder",
84
+ "RetrievalResult",
85
+ "Retriever",
86
+ "RetrieverProfile",
87
+ "SQLiteFTS5Retriever",
88
+ "SentenceTransformerDenseRetriever",
89
+ "TransformersBackend",
90
+ "Usage",
91
+ "UserRequest",
92
+ "UserResponder",
93
+ "UserResponse",
94
+ "VectorSearcher",
95
+ "build_retriever",
96
+ "require_capabilities",
97
+ "retriever_profile",
98
+ ]
@@ -0,0 +1,25 @@
1
+ """Standard embedding seams and dependency-free fixture implementations."""
2
+
3
+ from .base import (
4
+ EmbeddingBackend,
5
+ EmbeddingRequest,
6
+ EmbeddingResponse,
7
+ EmbeddingUsage,
8
+ normalize_vector,
9
+ validate_embedding_response,
10
+ )
11
+ from .callable import CallableEmbeddingBackend, EmbeddingClient
12
+ from .replay import DeterministicHashEmbeddingBackend, ReplayEmbeddingBackend
13
+
14
+ __all__ = [
15
+ "CallableEmbeddingBackend",
16
+ "DeterministicHashEmbeddingBackend",
17
+ "EmbeddingBackend",
18
+ "EmbeddingClient",
19
+ "EmbeddingRequest",
20
+ "EmbeddingResponse",
21
+ "EmbeddingUsage",
22
+ "ReplayEmbeddingBackend",
23
+ "normalize_vector",
24
+ "validate_embedding_response",
25
+ ]
@@ -0,0 +1,145 @@
1
+ """Backend-neutral embedding request, response, and validation contracts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ from collections.abc import Mapping
7
+ from dataclasses import dataclass, field
8
+ from typing import Any, Protocol, runtime_checkable
9
+
10
+ from agentinputlab.contracts.errors import ValidationError
11
+ from agentinputlab.contracts.serialization import content_hash, freeze_mapping
12
+
13
+
14
+ def _is_finite_nonnegative_number(value: Any) -> bool:
15
+ if isinstance(value, bool) or not isinstance(value, (int, float)):
16
+ return False
17
+ try:
18
+ return math.isfinite(value) and value >= 0
19
+ except (OverflowError, TypeError, ValueError):
20
+ return False
21
+
22
+
23
+ @dataclass(frozen=True, slots=True)
24
+ class EmbeddingRequest:
25
+ texts: tuple[str, ...]
26
+ normalize: bool = False
27
+ dimensions: int | None = None
28
+ metadata: Mapping[str, Any] = field(default_factory=dict)
29
+
30
+ def __post_init__(self) -> None:
31
+ object.__setattr__(self, "texts", tuple(self.texts))
32
+ object.__setattr__(self, "metadata", freeze_mapping(self.metadata))
33
+ if not all(isinstance(text, str) for text in self.texts):
34
+ raise ValidationError("embedding request texts must all be strings")
35
+ if self.dimensions is not None and self.dimensions < 1:
36
+ raise ValidationError("embedding request dimensions must be positive")
37
+
38
+ @property
39
+ def request_hash(self) -> str:
40
+ return content_hash(self)
41
+
42
+
43
+ @dataclass(frozen=True, slots=True)
44
+ class EmbeddingUsage:
45
+ input_count: int = 0
46
+ input_tokens: int | None = None
47
+ cost_usd: float | None = None
48
+
49
+ def __post_init__(self) -> None:
50
+ if isinstance(self.input_count, bool) or not isinstance(self.input_count, int):
51
+ raise ValidationError("embedding usage input_count must be a non-negative integer")
52
+ if self.input_count < 0:
53
+ raise ValidationError("embedding usage input_count must be a non-negative integer")
54
+ if self.input_tokens is not None and (
55
+ isinstance(self.input_tokens, bool)
56
+ or not isinstance(self.input_tokens, int)
57
+ or self.input_tokens < 0
58
+ ):
59
+ raise ValidationError(
60
+ "embedding usage input_tokens must be a non-negative integer or None"
61
+ )
62
+ if self.cost_usd is not None and not _is_finite_nonnegative_number(self.cost_usd):
63
+ raise ValidationError(
64
+ "embedding usage cost_usd must be finite and non-negative or None"
65
+ )
66
+
67
+
68
+ @dataclass(frozen=True, slots=True)
69
+ class EmbeddingResponse:
70
+ vectors: tuple[tuple[float, ...], ...]
71
+ model: str = ""
72
+ usage: EmbeddingUsage = field(default_factory=EmbeddingUsage)
73
+ metadata: Mapping[str, Any] = field(default_factory=dict)
74
+
75
+ def __post_init__(self) -> None:
76
+ vectors = tuple(tuple(float(value) for value in vector) for vector in self.vectors)
77
+ object.__setattr__(self, "vectors", vectors)
78
+ object.__setattr__(self, "metadata", freeze_mapping(self.metadata))
79
+ dimensions = {len(vector) for vector in vectors}
80
+ if len(dimensions) > 1:
81
+ raise ValidationError("embedding response vectors have inconsistent dimensions")
82
+ if vectors and dimensions == {0}:
83
+ raise ValidationError("embedding response vectors must not be empty")
84
+ if any(not math.isfinite(value) for vector in vectors for value in vector):
85
+ raise ValidationError("embedding response contains a non-finite value")
86
+
87
+ @property
88
+ def dimensions(self) -> int | None:
89
+ return len(self.vectors[0]) if self.vectors else None
90
+
91
+
92
+ @runtime_checkable
93
+ class EmbeddingBackend(Protocol):
94
+ model_id: str
95
+
96
+ def embed(self, request: EmbeddingRequest) -> EmbeddingResponse:
97
+ """Embed a batch without changing input order."""
98
+
99
+ def fingerprint(self) -> Mapping[str, Any]:
100
+ """Return stable, secret-free identity fields."""
101
+
102
+
103
+ def normalize_vector(vector: tuple[float, ...]) -> tuple[float, ...]:
104
+ norm = math.sqrt(sum(value * value for value in vector))
105
+ if norm == 0:
106
+ return vector
107
+ return tuple(value / norm for value in vector)
108
+
109
+
110
+ def validate_embedding_response(
111
+ request: EmbeddingRequest,
112
+ response: EmbeddingResponse,
113
+ *,
114
+ backend_dimensions: int | None = None,
115
+ ) -> EmbeddingResponse:
116
+ if len(response.vectors) != len(request.texts):
117
+ raise ValidationError(
118
+ "embedding response count does not match request: "
119
+ f"{len(response.vectors)} != {len(request.texts)}"
120
+ )
121
+ required_dimensions = request.dimensions or backend_dimensions
122
+ if required_dimensions is not None and any(
123
+ len(vector) != required_dimensions for vector in response.vectors
124
+ ):
125
+ raise ValidationError(
126
+ f"embedding response dimension does not match required {required_dimensions}"
127
+ )
128
+ if request.normalize:
129
+ return EmbeddingResponse(
130
+ vectors=tuple(normalize_vector(vector) for vector in response.vectors),
131
+ model=response.model,
132
+ usage=response.usage,
133
+ metadata=response.metadata,
134
+ )
135
+ return response
136
+
137
+
138
+ __all__ = [
139
+ "EmbeddingBackend",
140
+ "EmbeddingRequest",
141
+ "EmbeddingResponse",
142
+ "EmbeddingUsage",
143
+ "normalize_vector",
144
+ "validate_embedding_response",
145
+ ]
@@ -0,0 +1,75 @@
1
+ """Embedding backend using an explicitly injected callable client."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable, Iterable, Mapping
6
+ from dataclasses import dataclass, field
7
+ from typing import Any
8
+
9
+ from agentinputlab.contracts.errors import ValidationError
10
+ from agentinputlab.contracts.serialization import content_hash, freeze_mapping
11
+
12
+ from .base import (
13
+ EmbeddingBackend,
14
+ EmbeddingRequest,
15
+ EmbeddingResponse,
16
+ EmbeddingUsage,
17
+ validate_embedding_response,
18
+ )
19
+
20
+ EmbeddingClient = Callable[
21
+ [EmbeddingRequest],
22
+ EmbeddingResponse | Iterable[Iterable[float]],
23
+ ]
24
+
25
+
26
+ @dataclass(slots=True)
27
+ class CallableEmbeddingBackend(EmbeddingBackend):
28
+ """Adapt a local function, SDK client, RPC bridge, or test double.
29
+
30
+ The callable itself is never fingerprinted through ``repr``. Callers must
31
+ supply stable identity fields for any behavior that affects an experiment.
32
+ """
33
+
34
+ client: EmbeddingClient
35
+ model_id: str
36
+ revision: str = "unversioned"
37
+ dimensions: int | None = None
38
+ identity: Mapping[str, Any] = field(default_factory=dict)
39
+ network: bool = False
40
+
41
+ def __post_init__(self) -> None:
42
+ if not self.revision or self.revision == "unversioned":
43
+ raise ValidationError("callable embedding requires an explicit stable revision")
44
+ if not self.identity:
45
+ raise ValidationError("callable embedding requires explicit identity fields")
46
+ self.identity = freeze_mapping(self.identity)
47
+
48
+ def embed(self, request: EmbeddingRequest) -> EmbeddingResponse:
49
+ raw = self.client(request)
50
+ if isinstance(raw, EmbeddingResponse):
51
+ response = raw
52
+ else:
53
+ response = EmbeddingResponse(
54
+ vectors=tuple(tuple(float(value) for value in vector) for vector in raw),
55
+ model=self.model_id,
56
+ usage=EmbeddingUsage(input_count=len(request.texts)),
57
+ )
58
+ return validate_embedding_response(
59
+ request,
60
+ response,
61
+ backend_dimensions=self.dimensions,
62
+ )
63
+
64
+ def fingerprint(self) -> Mapping[str, Any]:
65
+ return {
66
+ "backend": "agentinputlab.callable_embedding.v1",
67
+ "model_id": self.model_id,
68
+ "revision": self.revision,
69
+ "dimensions": self.dimensions,
70
+ "identity_hash": content_hash(self.identity),
71
+ "network": self.network,
72
+ }
73
+
74
+
75
+ __all__ = ["CallableEmbeddingBackend", "EmbeddingClient"]
@@ -0,0 +1,129 @@
1
+ """Offline replay and deterministic fixture embedding backends."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ from collections.abc import Mapping, Sequence
7
+ from dataclasses import dataclass, field
8
+ from typing import Any
9
+
10
+ from agentinputlab.contracts.errors import ValidationError
11
+ from agentinputlab.contracts.serialization import content_hash
12
+
13
+ from .base import (
14
+ EmbeddingBackend,
15
+ EmbeddingRequest,
16
+ EmbeddingResponse,
17
+ EmbeddingUsage,
18
+ validate_embedding_response,
19
+ )
20
+
21
+
22
+ @dataclass(slots=True)
23
+ class ReplayEmbeddingBackend(EmbeddingBackend):
24
+ """Replay exact text-to-vector fixtures; missing texts fail closed."""
25
+
26
+ vectors: Mapping[str, Sequence[float]]
27
+ model_id: str = "replay-embedding"
28
+ revision: str = "fixture-v1"
29
+ _vectors: Mapping[str, tuple[float, ...]] = field(init=False, repr=False)
30
+ _dimensions: int | None = field(init=False, repr=False)
31
+
32
+ def __post_init__(self) -> None:
33
+ converted = {
34
+ text: tuple(float(value) for value in vector) for text, vector in self.vectors.items()
35
+ }
36
+ EmbeddingResponse(vectors=tuple(converted.values()), model=self.model_id)
37
+ dimensions = {len(vector) for vector in converted.values()}
38
+ if len(dimensions) > 1:
39
+ raise ValidationError("replay embedding fixtures have inconsistent dimensions")
40
+ self._vectors = converted
41
+ self._dimensions = next(iter(dimensions), None)
42
+
43
+ def embed(self, request: EmbeddingRequest) -> EmbeddingResponse:
44
+ missing = [text for text in request.texts if text not in self._vectors]
45
+ if missing:
46
+ raise ValidationError(
47
+ f"replay embedding fixture is missing {len(missing)} requested text(s)"
48
+ )
49
+ response = EmbeddingResponse(
50
+ vectors=tuple(self._vectors[text] for text in request.texts),
51
+ model=self.model_id,
52
+ usage=EmbeddingUsage(input_count=len(request.texts)),
53
+ metadata={"replay": True},
54
+ )
55
+ return validate_embedding_response(
56
+ request,
57
+ response,
58
+ backend_dimensions=self._dimensions,
59
+ )
60
+
61
+ def fingerprint(self) -> Mapping[str, Any]:
62
+ fixtures = [(text, self._vectors[text]) for text in sorted(self._vectors)]
63
+ return {
64
+ "backend": "agentinputlab.replay_embedding.v1",
65
+ "model_id": self.model_id,
66
+ "revision": self.revision,
67
+ "dimensions": self._dimensions,
68
+ "fixture_count": len(fixtures),
69
+ "fixture_hash": content_hash(fixtures),
70
+ "network": False,
71
+ }
72
+
73
+
74
+ @dataclass(frozen=True, slots=True)
75
+ class DeterministicHashEmbeddingBackend(EmbeddingBackend):
76
+ """Small dependency-free embedding backend for tests only."""
77
+
78
+ model_id: str = "fixture-hash-embedding"
79
+ dimensions: int = 32
80
+ salt: str = "agentinputlab-v1"
81
+
82
+ def __post_init__(self) -> None:
83
+ if self.dimensions < 1:
84
+ raise ValidationError("hash embedding dimensions must be positive")
85
+
86
+ def _vector(self, text: str) -> tuple[float, ...]:
87
+ values: list[float] = []
88
+ counter = 0
89
+ while len(values) < self.dimensions:
90
+ payload = f"{self.salt}\0{counter}\0{text}".encode()
91
+ digest = hashlib.sha256(payload).digest()
92
+ for offset in range(0, len(digest), 4):
93
+ integer = int.from_bytes(digest[offset : offset + 4], "big")
94
+ values.append((integer / 0xFFFFFFFF) * 2.0 - 1.0)
95
+ if len(values) == self.dimensions:
96
+ break
97
+ counter += 1
98
+ return tuple(values)
99
+
100
+ def embed(self, request: EmbeddingRequest) -> EmbeddingResponse:
101
+ if request.dimensions is not None and request.dimensions != self.dimensions:
102
+ raise ValidationError(
103
+ f"hash embedding dimension is fixed at {self.dimensions}, "
104
+ f"requested {request.dimensions}"
105
+ )
106
+ response = EmbeddingResponse(
107
+ vectors=tuple(self._vector(text) for text in request.texts),
108
+ model=self.model_id,
109
+ usage=EmbeddingUsage(input_count=len(request.texts)),
110
+ metadata={"fixture_only": True},
111
+ )
112
+ return validate_embedding_response(
113
+ request,
114
+ response,
115
+ backend_dimensions=self.dimensions,
116
+ )
117
+
118
+ def fingerprint(self) -> Mapping[str, Any]:
119
+ return {
120
+ "backend": "agentinputlab.hash_embedding.v1",
121
+ "model_id": self.model_id,
122
+ "dimensions": self.dimensions,
123
+ "salt_hash": content_hash(self.salt),
124
+ "fixture_only": True,
125
+ "network": False,
126
+ }
127
+
128
+
129
+ __all__ = ["DeterministicHashEmbeddingBackend", "ReplayEmbeddingBackend"]
@@ -0,0 +1,31 @@
1
+ """Language-model backend implementations."""
2
+
3
+ from .base import (
4
+ GenerationRequest,
5
+ GenerationResponse,
6
+ LLMBackend,
7
+ ModelCapability,
8
+ Usage,
9
+ require_capabilities,
10
+ )
11
+ from .callable import CallableBackend, ReplayBackend
12
+ from .decomp_completion import DecompCompletionBackend
13
+ from .final_content_stop import FINAL_CONTENT_STOP_POLICY_ID, FinalContentStopBackend
14
+ from .openai_compatible import OpenAICompatibleBackend
15
+ from .transformers import TransformersBackend
16
+
17
+ __all__ = [
18
+ "FINAL_CONTENT_STOP_POLICY_ID",
19
+ "CallableBackend",
20
+ "DecompCompletionBackend",
21
+ "FinalContentStopBackend",
22
+ "GenerationRequest",
23
+ "GenerationResponse",
24
+ "LLMBackend",
25
+ "ModelCapability",
26
+ "OpenAICompatibleBackend",
27
+ "ReplayBackend",
28
+ "TransformersBackend",
29
+ "Usage",
30
+ "require_capabilities",
31
+ ]