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,332 @@
1
+ """OpenAI-compatible backend for hosted APIs and self-hosted vLLM servers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import http.client
6
+ import json
7
+ import os
8
+ import urllib.error
9
+ import urllib.parse
10
+ import urllib.request
11
+ from collections.abc import Callable, Mapping
12
+ from contextlib import suppress
13
+ from dataclasses import dataclass, field
14
+ from typing import Any
15
+
16
+ from agentinputlab.contracts.errors import CapabilityError, ValidationError
17
+ from agentinputlab.contracts.serialization import content_hash, freeze_mapping, to_jsonable
18
+
19
+ from .base import (
20
+ GenerationRequest,
21
+ GenerationResponse,
22
+ LLMBackend,
23
+ ModelCapability,
24
+ Usage,
25
+ )
26
+
27
+ Transport = Callable[[str, Mapping[str, str], Mapping[str, Any], float], Mapping[str, Any]]
28
+ _MAX_RESPONSE_BYTES = 16 * 1024 * 1024
29
+ _SENSITIVE_EXTRA_HEADERS = frozenset(
30
+ {
31
+ "api-key",
32
+ "authorization",
33
+ "cookie",
34
+ "proxy-authorization",
35
+ "set-cookie",
36
+ "x-amz-security-token",
37
+ "x-api-key",
38
+ "x-auth-token",
39
+ "x-goog-api-key",
40
+ }
41
+ )
42
+ _TRANSPORT_ATTEMPT_POLICY = "single_transport_no_implicit_retry.v1"
43
+
44
+
45
+ class _OpenAICompatibleHTTPStatusError(RuntimeError):
46
+ """Sanitized status-only failure without remote response content."""
47
+
48
+ def __init__(self, status: int) -> None:
49
+ self.status = status
50
+ super().__init__(f"OpenAI-compatible endpoint returned HTTP {status}")
51
+
52
+
53
+ class _NoRedirectHandler(urllib.request.HTTPRedirectHandler):
54
+ def redirect_request(self, req, fp, code, msg, headers, newurl):
55
+ return None
56
+
57
+
58
+ def _default_transport(
59
+ url: str,
60
+ headers: Mapping[str, str],
61
+ payload: Mapping[str, Any],
62
+ timeout_seconds: float,
63
+ ) -> Mapping[str, Any]:
64
+ body = json.dumps(payload).encode("utf-8")
65
+ request = urllib.request.Request(url, data=body, headers=dict(headers), method="POST")
66
+ opener = urllib.request.build_opener(_NoRedirectHandler())
67
+ http_status: int | None = None
68
+ endpoint_unavailable = False
69
+ protocol_failure = False
70
+ try:
71
+ with opener.open(request, timeout=timeout_seconds) as response:
72
+ raw = response.read(_MAX_RESPONSE_BYTES + 1)
73
+ if len(raw) > _MAX_RESPONSE_BYTES:
74
+ raise RuntimeError("OpenAI-compatible response exceeds the size limit")
75
+ return json.loads(raw.decode("utf-8"))
76
+ except urllib.error.HTTPError as exc:
77
+ # A remote endpoint can reflect Authorization values or other opaque
78
+ # request material in its error body. Never copy that untrusted body
79
+ # into exceptions because experiment monitors may persist them.
80
+ http_status = exc.code
81
+ # Cleanup diagnostics are remote/transport-controlled too; the fixed
82
+ # status-only error below remains the sole public message.
83
+ with suppress(Exception):
84
+ exc.close()
85
+ except urllib.error.URLError:
86
+ # ``reason`` is likewise remote/transport-controlled and may contain a
87
+ # credential-bearing URL. Keep the diagnostic intentionally generic.
88
+ endpoint_unavailable = True
89
+ except http.client.HTTPException:
90
+ # Invalid status lines and incomplete HTTP frames can embed raw,
91
+ # remote-controlled bytes in their exception text.
92
+ protocol_failure = True
93
+ # Raise after leaving the handler so neither ``__cause__`` nor
94
+ # ``__context__`` retains the remote-controlled exception for traceback
95
+ # loggers to render.
96
+ if http_status is not None:
97
+ raise _OpenAICompatibleHTTPStatusError(http_status)
98
+ if endpoint_unavailable:
99
+ raise RuntimeError("OpenAI-compatible endpoint is unavailable")
100
+ if protocol_failure:
101
+ raise RuntimeError("OpenAI-compatible endpoint returned an invalid HTTP response")
102
+ raise RuntimeError("OpenAI-compatible transport failed without a diagnostic")
103
+
104
+
105
+ @dataclass(slots=True)
106
+ class OpenAICompatibleBackend(LLMBackend):
107
+ model_id: str
108
+ base_url: str
109
+ deployment_identity: Mapping[str, Any] = field(default_factory=dict)
110
+ api_key: str | None = field(default=None, repr=False)
111
+ api_key_env: str = "OPENAI_API_KEY"
112
+ timeout_seconds: float = 120.0
113
+ extra_headers: Mapping[str, str] = field(default_factory=dict, repr=False)
114
+ extra_body: Mapping[str, Any] = field(default_factory=dict, repr=False)
115
+ capabilities: frozenset[ModelCapability] = frozenset(
116
+ {
117
+ ModelCapability.CHAT,
118
+ ModelCapability.COMPLETION,
119
+ ModelCapability.JSON_OBJECT,
120
+ ModelCapability.TOOL_CALLING,
121
+ ModelCapability.SEED,
122
+ }
123
+ )
124
+ transport: Transport = _default_transport
125
+
126
+ def __post_init__(self) -> None:
127
+ parsed = urllib.parse.urlparse(self.base_url)
128
+ if parsed.scheme not in {"http", "https"} or not parsed.netloc:
129
+ raise ValidationError("base_url must be an absolute http(s) URL")
130
+ if parsed.username or parsed.password or parsed.query or parsed.fragment:
131
+ raise ValidationError("base_url must not contain credentials, query, or fragment")
132
+ if not self.deployment_identity or not self.deployment_identity.get("revision"):
133
+ raise ValidationError("OpenAI-compatible backend requires deployment_identity.revision")
134
+ for name, value in self.extra_headers.items():
135
+ if not isinstance(name, str) or not isinstance(value, str):
136
+ raise ValidationError("OpenAI-compatible extra headers must contain strings")
137
+ if name.casefold() in _SENSITIVE_EXTRA_HEADERS:
138
+ raise ValidationError(
139
+ f"sensitive extra header {name!r} is forbidden; use api_key or api_key_env"
140
+ )
141
+ self.base_url = self.base_url.rstrip("/")
142
+ self.deployment_identity = freeze_mapping(self.deployment_identity)
143
+ self.extra_headers = freeze_mapping(self.extra_headers)
144
+ self.extra_body = freeze_mapping(self.extra_body)
145
+ self.capabilities = frozenset(self.capabilities)
146
+
147
+ def generate(self, request: GenerationRequest) -> GenerationResponse:
148
+ if request.tools and ModelCapability.TOOL_CALLING not in self.capabilities:
149
+ raise CapabilityError(f"backend {self.model_id!r} does not support tools")
150
+ if request.seed is not None and ModelCapability.SEED not in self.capabilities:
151
+ raise CapabilityError(f"backend {self.model_id!r} does not support seed")
152
+ if request.logprobs and ModelCapability.LOGPROBS not in self.capabilities:
153
+ raise CapabilityError(f"backend {self.model_id!r} does not support logprobs")
154
+ if (
155
+ request.response_format
156
+ and ModelCapability.JSON_OBJECT not in self.capabilities
157
+ and ModelCapability.JSON_SCHEMA not in self.capabilities
158
+ ):
159
+ raise CapabilityError(f"backend {self.model_id!r} does not support response_format")
160
+ messages: list[dict[str, str]] = []
161
+ if request.system:
162
+ messages.append({"role": "system", "content": request.system})
163
+ if request.messages:
164
+ for message in request.messages:
165
+ item = {"role": message.role, "content": message.content}
166
+ if message.name:
167
+ item["name"] = message.name
168
+ messages.append(item)
169
+ elif request.prompt:
170
+ messages.append({"role": "user", "content": request.prompt})
171
+
172
+ payload: dict[str, Any] = {
173
+ **dict(self.extra_body),
174
+ "model": self.model_id,
175
+ "messages": messages,
176
+ "temperature": request.temperature,
177
+ "max_tokens": request.max_tokens,
178
+ }
179
+ if request.seed is not None:
180
+ payload["seed"] = request.seed
181
+ if request.stop:
182
+ payload["stop"] = list(request.stop)
183
+ if request.logprobs:
184
+ payload["logprobs"] = True
185
+ if request.top_logprobs is not None:
186
+ payload["top_logprobs"] = request.top_logprobs
187
+ if request.response_format:
188
+ payload["response_format"] = dict(request.response_format)
189
+ if request.tools:
190
+ payload["tools"] = list(request.tools)
191
+
192
+ # ``freeze_mapping`` recursively protects backend/request contracts,
193
+ # so nested values may be MappingProxyType instances. Materialize the
194
+ # complete payload—not just its outer mapping—before handing it to a
195
+ # custom transport or ``json.dumps``.
196
+ payload = dict(to_jsonable(payload))
197
+
198
+ key = self.api_key or os.environ.get(self.api_key_env, "")
199
+ headers = {"Content-Type": "application/json", **dict(self.extra_headers)}
200
+ if key:
201
+ headers["Authorization"] = f"Bearer {key}"
202
+ data: Mapping[str, Any] | None = None
203
+ transport_failed = False
204
+ try:
205
+ data = self.transport(
206
+ f"{self.base_url}/chat/completions",
207
+ headers,
208
+ payload,
209
+ self.timeout_seconds,
210
+ )
211
+ except Exception:
212
+ # Custom transports are an extension boundary and may raise
213
+ # exceptions containing request headers or provider bodies. Do
214
+ # not let their text or traceback context enter run artifacts.
215
+ transport_failed = True
216
+ if transport_failed:
217
+ # A failed request may already have generated/billed tokens. Do
218
+ # not hide another model attempt inside one budget reservation,
219
+ # or replace its unknown usage with a successful retry's usage.
220
+ raise RuntimeError("OpenAI-compatible transport failed")
221
+ if key and _contains_exact_text(data, key):
222
+ raise RuntimeError("OpenAI-compatible response contains the configured credential")
223
+ response: GenerationResponse | None = None
224
+ schema_error = False
225
+ try:
226
+ response = _parse_generation_response(data, fallback_model=self.model_id)
227
+ except (AttributeError, IndexError, KeyError, OverflowError, TypeError, ValueError):
228
+ schema_error = True
229
+ # Leave the handler before raising so remote-controlled values cannot
230
+ # survive in an exception context rendered by a traceback logger.
231
+ if schema_error or response is None:
232
+ raise RuntimeError("OpenAI-compatible response schema is invalid")
233
+ return response
234
+
235
+ def fingerprint(self) -> Mapping[str, Any]:
236
+ parsed = urllib.parse.urlparse(self.base_url)
237
+ identity = {
238
+ "backend": "openai_compatible",
239
+ "model_id": self.model_id,
240
+ "endpoint_origin": f"{parsed.scheme}://{parsed.netloc}",
241
+ "base_url": self.base_url,
242
+ "deployment_identity_hash": content_hash(self.deployment_identity),
243
+ "capabilities": sorted(item.value for item in self.capabilities),
244
+ "extra_body_hash": content_hash(self.extra_body),
245
+ "extra_header_names": sorted(self.extra_headers),
246
+ "extra_headers_hash": content_hash(self.extra_headers),
247
+ "transport_attempt_policy": _TRANSPORT_ATTEMPT_POLICY,
248
+ }
249
+ revision = self.deployment_identity.get("revision")
250
+ if isinstance(revision, str) and revision.strip():
251
+ # Source-bound workers need the declared public revision as well as
252
+ # its deployment hash. Never expose the entire operator mapping.
253
+ identity["model_revision"] = revision
254
+ return identity
255
+
256
+
257
+ def _parse_generation_response(
258
+ data: Any,
259
+ *,
260
+ fallback_model: str,
261
+ ) -> GenerationResponse:
262
+ if not isinstance(data, Mapping):
263
+ raise TypeError("response must be a mapping")
264
+ choices = data.get("choices")
265
+ if not isinstance(choices, list) or not choices:
266
+ raise ValueError("response choices must be a non-empty list")
267
+ choice = choices[0]
268
+ if not isinstance(choice, Mapping):
269
+ raise TypeError("response choice must be a mapping")
270
+ message = choice.get("message")
271
+ text: Any = None
272
+ if message is not None:
273
+ if not isinstance(message, Mapping):
274
+ raise TypeError("response message must be a mapping")
275
+ text = message.get("content")
276
+ if text is None:
277
+ text = choice.get("text", "")
278
+ if not isinstance(text, str):
279
+ raise TypeError("response text must be a string")
280
+ model = data.get("model", fallback_model)
281
+ if not isinstance(model, str):
282
+ raise TypeError("response model must be a string")
283
+ finish_reason = choice.get("finish_reason", "")
284
+ if finish_reason is None:
285
+ finish_reason = ""
286
+ if not isinstance(finish_reason, str):
287
+ raise TypeError("response finish_reason must be a string")
288
+ usage = data.get("usage", {})
289
+ if usage is None:
290
+ usage = {}
291
+ if not isinstance(usage, Mapping):
292
+ raise TypeError("response usage must be a mapping")
293
+ return GenerationResponse(
294
+ text=text,
295
+ model=model,
296
+ finish_reason=finish_reason,
297
+ usage=Usage(
298
+ input_tokens=_response_token_count(usage.get("prompt_tokens", 0)),
299
+ output_tokens=_response_token_count(usage.get("completion_tokens", 0)),
300
+ ),
301
+ raw=data,
302
+ )
303
+
304
+
305
+ def _response_token_count(value: Any) -> int:
306
+ if isinstance(value, bool) or not isinstance(value, int) or value < 0:
307
+ raise ValueError("response token count must be a non-negative integer")
308
+ return value
309
+
310
+
311
+ def _contains_exact_text(value: Any, needle: str, *, _seen: set[int] | None = None) -> bool:
312
+ if isinstance(value, str):
313
+ return needle in value
314
+ if isinstance(value, Mapping):
315
+ seen = set() if _seen is None else _seen
316
+ identity = id(value)
317
+ if identity in seen:
318
+ return False
319
+ seen.add(identity)
320
+ return any(
321
+ (isinstance(key, str) and needle in key)
322
+ or _contains_exact_text(item, needle, _seen=seen)
323
+ for key, item in value.items()
324
+ )
325
+ if isinstance(value, (list, tuple)):
326
+ seen = set() if _seen is None else _seen
327
+ identity = id(value)
328
+ if identity in seen:
329
+ return False
330
+ seen.add(identity)
331
+ return any(_contains_exact_text(item, needle, _seen=seen) for item in value)
332
+ return False
@@ -0,0 +1,171 @@
1
+ """Optional local Transformers backend loaded without a hard runtime dependency."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from dataclasses import dataclass, field
7
+ from typing import Any
8
+
9
+ from agentinputlab.contracts.errors import CapabilityError, ExternalDependencyError, ValidationError
10
+ from agentinputlab.contracts.serialization import freeze_mapping
11
+
12
+ from .base import GenerationRequest, GenerationResponse, LLMBackend, ModelCapability, Usage
13
+
14
+
15
+ @dataclass(slots=True)
16
+ class TransformersBackend(LLMBackend):
17
+ model_id: str
18
+ model_revision: str
19
+ tokenizer_revision: str
20
+ tokenizer: Any = None
21
+ model: Any = None
22
+ generation_kwargs: Mapping[str, Any] = field(default_factory=dict)
23
+ cache_dir: str | None = None
24
+ offline: bool = False
25
+ capabilities: frozenset[ModelCapability] = frozenset(
26
+ {ModelCapability.CHAT, ModelCapability.COMPLETION}
27
+ )
28
+
29
+ def __post_init__(self) -> None:
30
+ if not isinstance(self.offline, bool):
31
+ raise ValidationError("TransformersBackend offline must be boolean")
32
+ if self.cache_dir is not None and (
33
+ not isinstance(self.cache_dir, str) or not self.cache_dir.strip()
34
+ ):
35
+ raise ValidationError("TransformersBackend cache_dir must be a non-empty path string")
36
+ if not self.model_revision or not self.tokenizer_revision:
37
+ raise ValidationError(
38
+ "TransformersBackend requires explicit model and tokenizer revisions"
39
+ )
40
+ self.generation_kwargs = freeze_mapping(self.generation_kwargs)
41
+ num_return_sequences = self.generation_kwargs.get("num_return_sequences", 1)
42
+ if (
43
+ isinstance(num_return_sequences, bool)
44
+ or not isinstance(num_return_sequences, int)
45
+ or num_return_sequences != 1
46
+ ):
47
+ raise ValidationError(
48
+ "TransformersBackend requires num_return_sequences to be the integer 1"
49
+ )
50
+ self.capabilities = frozenset(self.capabilities)
51
+
52
+ def _load(self) -> None:
53
+ if self.model is not None and self.tokenizer is not None:
54
+ return
55
+ try:
56
+ from transformers import AutoModelForCausalLM, AutoTokenizer
57
+ except ImportError as exc:
58
+ raise ExternalDependencyError(
59
+ "TransformersBackend requires `pip install agentinputlab[local]`"
60
+ ) from exc
61
+ self.tokenizer = AutoTokenizer.from_pretrained(
62
+ self.model_id,
63
+ revision=self.tokenizer_revision,
64
+ trust_remote_code=False,
65
+ cache_dir=self.cache_dir,
66
+ local_files_only=self.offline,
67
+ )
68
+ self.model = AutoModelForCausalLM.from_pretrained(
69
+ self.model_id,
70
+ revision=self.model_revision,
71
+ trust_remote_code=False,
72
+ cache_dir=self.cache_dir,
73
+ local_files_only=self.offline,
74
+ )
75
+
76
+ def generate(self, request: GenerationRequest) -> GenerationResponse:
77
+ if request.seed is not None and ModelCapability.SEED not in self.capabilities:
78
+ raise CapabilityError(
79
+ "TransformersBackend does not implement deterministic seed control"
80
+ )
81
+ if request.tools and ModelCapability.TOOL_CALLING not in self.capabilities:
82
+ raise CapabilityError("TransformersBackend does not support structured tool calling")
83
+ if request.response_format and not {
84
+ ModelCapability.JSON_OBJECT,
85
+ ModelCapability.JSON_SCHEMA,
86
+ }.intersection(self.capabilities):
87
+ raise CapabilityError("TransformersBackend does not support response_format")
88
+ self._load()
89
+ if request.messages and hasattr(self.tokenizer, "apply_chat_template"):
90
+ messages = []
91
+ if request.system:
92
+ messages.append({"role": "system", "content": request.system})
93
+ messages.extend(
94
+ {"role": item.role, "content": item.content} for item in request.messages
95
+ )
96
+ prompt = self.tokenizer.apply_chat_template(
97
+ messages,
98
+ tokenize=False,
99
+ add_generation_prompt=True,
100
+ )
101
+ elif request.messages:
102
+ raise CapabilityError(
103
+ "Transformers tokenizer has no chat template for message-based generation"
104
+ )
105
+ else:
106
+ prompt = f"{request.system}\n\n{request.prompt}" if request.system else request.prompt
107
+ inputs = self.tokenizer(prompt, return_tensors="pt")
108
+ outputs = self.model.generate(
109
+ **inputs,
110
+ max_new_tokens=request.max_tokens,
111
+ do_sample=request.temperature > 0,
112
+ temperature=max(request.temperature, 1e-5),
113
+ **dict(self.generation_kwargs),
114
+ )
115
+ sequences = outputs.sequences if hasattr(outputs, "sequences") else outputs
116
+ try:
117
+ input_shape = inputs["input_ids"].shape
118
+ if len(input_shape) != 2 or int(input_shape[0]) != 1:
119
+ raise ValueError("input_ids must contain exactly one two-dimensional sequence")
120
+ input_width = int(input_shape[1])
121
+ if input_width < 1:
122
+ raise ValueError("input_ids sequence must not be empty")
123
+
124
+ sequence_shape = sequences.shape
125
+ if len(sequence_shape) != 2 or int(sequence_shape[0]) != 1:
126
+ raise ValueError("generate must return exactly one two-dimensional sequence")
127
+ sequence_width = int(sequence_shape[1])
128
+ if sequence_width < input_width:
129
+ raise ValueError("generated sequence is shorter than its input")
130
+
131
+ generated_sequence = sequences[0]
132
+ new_tokens = generated_sequence[input_width:]
133
+ output_tokens = sequence_width - input_width
134
+ except (AttributeError, IndexError, KeyError, OverflowError, TypeError, ValueError) as exc:
135
+ raise ValidationError(
136
+ "Transformers model.generate returned an unsupported sequence shape"
137
+ ) from exc
138
+ attention_mask = inputs.get("attention_mask")
139
+ if attention_mask is None:
140
+ input_tokens = input_width
141
+ else:
142
+ try:
143
+ mask_shape = attention_mask.shape
144
+ if (
145
+ len(mask_shape) != 2
146
+ or int(mask_shape[0]) != 1
147
+ or int(mask_shape[1]) != input_width
148
+ ):
149
+ raise ValueError("attention_mask shape must match the single input sequence")
150
+ input_tokens = int(attention_mask.sum())
151
+ if input_tokens < 0 or input_tokens > input_width:
152
+ raise ValueError("attention_mask token count is outside the input width")
153
+ except (AttributeError, OverflowError, TypeError, ValueError) as exc:
154
+ raise ValidationError(
155
+ "Transformers tokenizer returned an unsupported attention_mask"
156
+ ) from exc
157
+ text = self.tokenizer.decode(new_tokens, skip_special_tokens=True)
158
+ return GenerationResponse(
159
+ text=text,
160
+ model=self.model_id,
161
+ usage=Usage(input_tokens=input_tokens, output_tokens=output_tokens),
162
+ )
163
+
164
+ def fingerprint(self) -> Mapping[str, Any]:
165
+ return {
166
+ "backend": "transformers",
167
+ "model_id": self.model_id,
168
+ "model_revision": self.model_revision,
169
+ "tokenizer_revision": self.tokenizer_revision,
170
+ "generation_kwargs": dict(self.generation_kwargs),
171
+ }
@@ -0,0 +1,35 @@
1
+ """Retrieval backend contracts and small deterministic implementations."""
2
+
3
+ from .base import Document, RetrievalResult, Retriever
4
+ from .dense import (
5
+ DENSE_RETRIEVER_PROFILE_IDS,
6
+ RETRIEVER_PROFILES,
7
+ BatchTextEncoder,
8
+ DenseIndexSummary,
9
+ EmbeddingBackendEncoder,
10
+ RetrieverProfile,
11
+ SentenceTransformerDenseRetriever,
12
+ build_retriever,
13
+ retriever_profile,
14
+ )
15
+ from .memory import FunctionRetriever, InMemoryBM25Retriever, default_tokenize
16
+ from .sqlite_fts import SQLiteFTS5Retriever
17
+
18
+ __all__ = [
19
+ "DENSE_RETRIEVER_PROFILE_IDS",
20
+ "RETRIEVER_PROFILES",
21
+ "BatchTextEncoder",
22
+ "DenseIndexSummary",
23
+ "Document",
24
+ "EmbeddingBackendEncoder",
25
+ "FunctionRetriever",
26
+ "InMemoryBM25Retriever",
27
+ "RetrievalResult",
28
+ "Retriever",
29
+ "RetrieverProfile",
30
+ "SQLiteFTS5Retriever",
31
+ "SentenceTransformerDenseRetriever",
32
+ "build_retriever",
33
+ "default_tokenize",
34
+ "retriever_profile",
35
+ ]
@@ -0,0 +1,50 @@
1
+ """Standard knowledge retrieval interfaces."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from dataclasses import dataclass, field
7
+ from typing import Any, Protocol, runtime_checkable
8
+
9
+ from agentinputlab.contracts.errors import ValidationError
10
+ from agentinputlab.contracts.serialization import freeze_mapping
11
+
12
+
13
+ @dataclass(frozen=True, slots=True)
14
+ class Document:
15
+ doc_id: str
16
+ text: str
17
+ title: str = ""
18
+ corpus_revision: str = ""
19
+ metadata: Mapping[str, Any] = field(default_factory=dict)
20
+
21
+ def __post_init__(self) -> None:
22
+ if not self.doc_id:
23
+ raise ValidationError("document requires a non-empty doc_id")
24
+ object.__setattr__(self, "metadata", freeze_mapping(self.metadata))
25
+
26
+
27
+ @dataclass(frozen=True, slots=True)
28
+ class RetrievalResult:
29
+ document: Document
30
+ score: float
31
+ rank: int
32
+ features: Mapping[str, float] = field(default_factory=dict)
33
+
34
+ def __post_init__(self) -> None:
35
+ if not isinstance(self.document, Document):
36
+ raise ValidationError("retrieval result requires a Document")
37
+ if self.rank < 1:
38
+ raise ValidationError("retrieval result rank must be positive")
39
+ object.__setattr__(self, "features", freeze_mapping(self.features))
40
+
41
+
42
+ @runtime_checkable
43
+ class Retriever(Protocol):
44
+ retriever_id: str
45
+
46
+ def retrieve(self, query: str, *, top_k: int = 5) -> tuple[RetrievalResult, ...]:
47
+ """Return deterministic ranked candidates."""
48
+
49
+ def fingerprint(self) -> Mapping[str, Any]:
50
+ """Return corpus/index/retriever identity for balance auditing."""