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,444 @@
1
+ """Create-only, versioned storage for non-blocking measurement audits."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ import os
8
+ import tempfile
9
+ from collections.abc import Mapping, Sequence
10
+ from datetime import datetime, timezone
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ from agentinputlab.contracts.serialization import canonical_json, content_hash
15
+
16
+ ANNOTATION_VERSION_PROTOCOL = "agentinputlab.annotation-version.v1"
17
+ ANNOTATION_SELECTION_PROTOCOL = "agentinputlab.annotation-selection.v1"
18
+ ANNOTATION_KINDS = frozenset({"input_audit", "trajectory_audit"})
19
+
20
+
21
+ class AnnotationStoreError(ValueError):
22
+ """Raised when an annotation version would be ambiguous or mutable."""
23
+
24
+
25
+ def validate_annotation_selection(
26
+ root: str | Path,
27
+ *,
28
+ kind: str,
29
+ ) -> Mapping[str, Any] | None:
30
+ """Return the selected completed audit version, or fail on ambiguity.
31
+
32
+ Automatic measurements do not require a human audit to exist. Once at
33
+ least one completed audit does exist, however, experiment and plotting
34
+ entry points must bind an explicit selection receipt instead of silently
35
+ choosing the newest file on disk.
36
+ """
37
+
38
+ if kind not in ANNOTATION_KINDS:
39
+ raise AnnotationStoreError("annotation kind must be input_audit or trajectory_audit")
40
+ root_path = Path(root).expanduser().resolve()
41
+ if root_path.is_symlink():
42
+ raise AnnotationStoreError("annotation root must not be a symbolic link")
43
+ if not root_path.exists():
44
+ return None
45
+ if not root_path.is_dir():
46
+ raise AnnotationStoreError("annotation root must be a directory")
47
+
48
+ completed: dict[str, Mapping[str, Any]] = {}
49
+ for path in sorted(root_path.glob(f"{kind}-v[0-9][0-9][0-9]/manifest.json")):
50
+ value = _read_json(path)
51
+ items_hash = value.get("items_sha256")
52
+ if not isinstance(items_hash, str) or not items_hash:
53
+ raise AnnotationStoreError(f"annotation manifest has no items hash: {path}")
54
+ _validate_manifest(value, kind=kind, items_hash=items_hash)
55
+ if value["status"] == "complete":
56
+ annotations_path = path.parent / "annotations.jsonl"
57
+ if annotations_path.is_symlink() or not annotations_path.is_file():
58
+ raise AnnotationStoreError(
59
+ f"completed annotation data is unavailable: {annotations_path}"
60
+ )
61
+ if _sha256(annotations_path) != value.get("annotations_sha256"):
62
+ raise AnnotationStoreError(
63
+ f"completed annotation data hash does not match its manifest: {annotations_path}"
64
+ )
65
+ completed[str(value["version_id"])] = value
66
+ if not completed:
67
+ return None
68
+
69
+ selection_path = root_path / f"{kind}-selection.json"
70
+ if selection_path.is_symlink() or not selection_path.is_file():
71
+ versions = ", ".join(sorted(completed))
72
+ raise AnnotationStoreError(
73
+ f"completed {kind} annotation exists ({versions}) but no version is selected; "
74
+ "open agentinputlab-annotate or run select_annotation_version.py"
75
+ )
76
+ selection = _read_json(selection_path)
77
+ expected = selection.get("selection_hash")
78
+ unhashed = {key: item for key, item in selection.items() if key != "selection_hash"}
79
+ version_id = selection.get("version_id")
80
+ if (
81
+ selection.get("schema_version") != 1
82
+ or selection.get("protocol") != ANNOTATION_SELECTION_PROTOCOL
83
+ or selection.get("kind") != kind
84
+ or expected != content_hash(unhashed)
85
+ or version_id not in completed
86
+ ):
87
+ raise AnnotationStoreError(f"selected {kind} annotation receipt is invalid")
88
+ manifest = completed[str(version_id)]
89
+ if (
90
+ selection.get("version_manifest_hash") != manifest["manifest_hash"]
91
+ or selection.get("items_sha256") != manifest["items_sha256"]
92
+ or selection.get("annotations_sha256") != manifest["annotations_sha256"]
93
+ ):
94
+ raise AnnotationStoreError(f"selected {kind} annotation hashes do not match its version")
95
+ return dict(selection)
96
+
97
+
98
+ class AnnotationStore:
99
+ """Persist one local audit census in immutable, explicitly selected versions."""
100
+
101
+ def __init__(self, *, items_path: str | Path, root: str | Path, kind: str) -> None:
102
+ if kind not in ANNOTATION_KINDS:
103
+ raise AnnotationStoreError("annotation kind must be input_audit or trajectory_audit")
104
+ self.items_path = Path(items_path).expanduser().resolve()
105
+ self.root = Path(root).expanduser().resolve()
106
+ self.kind = kind
107
+ if self.items_path.is_symlink() or not self.items_path.is_file():
108
+ raise AnnotationStoreError(f"annotation item file is unavailable: {self.items_path}")
109
+ self.items = _load_items(self.items_path)
110
+ self.items_hash = _sha256(self.items_path)
111
+ self.root.mkdir(parents=True, exist_ok=True)
112
+
113
+ def status(self) -> dict[str, Any]:
114
+ versions = self.list_versions()
115
+ completed = [row for row in versions if row["status"] == "complete"]
116
+ selection = self._selection()
117
+ return {
118
+ "schema_version": 1,
119
+ "service": "agentinputlab-annotation",
120
+ "kind": self.kind,
121
+ "item_count": len(self.items),
122
+ "items_sha256": self.items_hash,
123
+ "versions": versions,
124
+ "completed_versions": len(completed),
125
+ "completed_version_exists": bool(completed),
126
+ "requires_reuse_or_new_version_choice": bool(completed),
127
+ "selected_version": selection["version_id"] if selection is not None else None,
128
+ "selection_path": str(self.selection_path),
129
+ "execution_depends_on_completion": False,
130
+ }
131
+
132
+ @property
133
+ def selection_path(self) -> Path:
134
+ return self.root / f"{self.kind}-selection.json"
135
+
136
+ def list_versions(self) -> list[dict[str, Any]]:
137
+ rows: list[dict[str, Any]] = []
138
+ for path in sorted(self.root.glob(f"{self.kind}-v[0-9][0-9][0-9]/manifest.json")):
139
+ try:
140
+ manifest = _read_json(path)
141
+ _validate_manifest(manifest, kind=self.kind, items_hash=self.items_hash)
142
+ except (OSError, ValueError, json.JSONDecodeError):
143
+ continue
144
+ rows.append(_public_manifest(manifest))
145
+ return rows
146
+
147
+ def create_version(self, *, annotator_id: str) -> dict[str, Any]:
148
+ annotator_id = _text(annotator_id, label="annotator_id")
149
+ existing = self.list_versions()
150
+ number = max((int(row["version_id"].rsplit("v", 1)[1]) for row in existing), default=0) + 1
151
+ version_id = f"{self.kind}-v{number:03d}"
152
+ directory = self.root / version_id
153
+ directory.mkdir(parents=False, exist_ok=False)
154
+ now = datetime.now(timezone.utc).isoformat()
155
+ without_hash = {
156
+ "schema_version": 1,
157
+ "protocol": ANNOTATION_VERSION_PROTOCOL,
158
+ "version_id": version_id,
159
+ "kind": self.kind,
160
+ "annotator_id": annotator_id,
161
+ "items_path": str(self.items_path),
162
+ "items_sha256": self.items_hash,
163
+ "item_count": len(self.items),
164
+ "annotation_count": 0,
165
+ "status": "in_progress",
166
+ "created_at": now,
167
+ "completed_at": None,
168
+ "annotations_sha256": None,
169
+ "supersedes_completed_version": any(row["status"] == "complete" for row in existing),
170
+ }
171
+ manifest = {**without_hash, "manifest_hash": content_hash(without_hash)}
172
+ _write_atomic(directory / "manifest.json", manifest)
173
+ _write_atomic(directory / "annotations.jsonl", b"")
174
+ return _public_manifest(manifest)
175
+
176
+ def payload(self, version_id: str) -> dict[str, Any]:
177
+ manifest = self._manifest(version_id)
178
+ annotations = self._annotations(version_id)
179
+ return {
180
+ "manifest": _public_manifest(manifest),
181
+ "items": self.items,
182
+ "annotations": annotations,
183
+ }
184
+
185
+ def save(self, version_id: str, annotation: Mapping[str, Any]) -> dict[str, Any]:
186
+ manifest = self._manifest(version_id)
187
+ if manifest["status"] == "complete":
188
+ raise AnnotationStoreError(
189
+ "completed annotations are immutable; create a new version to re-annotate"
190
+ )
191
+ item_id = _text(annotation.get("item_id"), label="annotation item_id")
192
+ if item_id not in {row["item_id"] for row in self.items}:
193
+ raise AnnotationStoreError("annotation item_id is outside the frozen audit census")
194
+ labels = annotation.get("labels")
195
+ if not isinstance(labels, Mapping) or not labels:
196
+ raise AnnotationStoreError("annotation labels must be a non-empty object")
197
+ if any(
198
+ not isinstance(key, str)
199
+ or not key
200
+ or not isinstance(value, (str, bool, int))
201
+ or (isinstance(value, str) and not value.strip())
202
+ for key, value in labels.items()
203
+ ):
204
+ raise AnnotationStoreError("annotation labels contain invalid values")
205
+ notes = annotation.get("notes", "")
206
+ if not isinstance(notes, str) or len(notes) > 4000:
207
+ raise AnnotationStoreError("annotation notes must be a string of at most 4000 chars")
208
+ rows = {row["item_id"]: row for row in self._annotations(version_id)}
209
+ row_without_hash = {
210
+ "schema_version": 1,
211
+ "version_id": version_id,
212
+ "kind": self.kind,
213
+ "item_id": item_id,
214
+ "annotator_id": manifest["annotator_id"],
215
+ "labels": dict(sorted(labels.items())),
216
+ "notes": notes,
217
+ "saved_at": datetime.now(timezone.utc).isoformat(),
218
+ }
219
+ rows[item_id] = {**row_without_hash, "annotation_hash": content_hash(row_without_hash)}
220
+ ordered = [rows[key] for key in sorted(rows)]
221
+ annotations_path = self.root / version_id / "annotations.jsonl"
222
+ _write_atomic(annotations_path, _jsonl_bytes(ordered))
223
+ updated = self._updated_manifest(
224
+ manifest,
225
+ annotation_count=len(ordered),
226
+ annotations_sha256=_sha256(annotations_path),
227
+ )
228
+ _write_atomic(self.root / version_id / "manifest.json", updated)
229
+ return {
230
+ "saved": True,
231
+ "version_id": version_id,
232
+ "item_id": item_id,
233
+ "annotation_count": len(ordered),
234
+ "item_count": len(self.items),
235
+ }
236
+
237
+ def complete(self, version_id: str) -> dict[str, Any]:
238
+ manifest = self._manifest(version_id)
239
+ if manifest["status"] == "complete":
240
+ return _public_manifest(manifest)
241
+ annotations = self._annotations(version_id)
242
+ observed = {row["item_id"] for row in annotations}
243
+ expected = {row["item_id"] for row in self.items}
244
+ if observed != expected:
245
+ raise AnnotationStoreError(
246
+ f"cannot complete annotation: {len(expected - observed)} audit items remain"
247
+ )
248
+ annotations_path = self.root / version_id / "annotations.jsonl"
249
+ updated = self._updated_manifest(
250
+ manifest,
251
+ annotation_count=len(annotations),
252
+ annotations_sha256=_sha256(annotations_path),
253
+ status="complete",
254
+ completed_at=datetime.now(timezone.utc).isoformat(),
255
+ )
256
+ _write_atomic(self.root / version_id / "manifest.json", updated)
257
+ return _public_manifest(updated)
258
+
259
+ def select(self, version_id: str, *, output: str | Path | None = None) -> dict[str, Any]:
260
+ manifest = self._manifest(version_id)
261
+ if manifest["status"] != "complete":
262
+ raise AnnotationStoreError("only a complete annotation version may be selected")
263
+ output_path = (
264
+ Path(output).expanduser().resolve() if output is not None else self.selection_path
265
+ )
266
+ without_hash = {
267
+ "schema_version": 1,
268
+ "protocol": ANNOTATION_SELECTION_PROTOCOL,
269
+ "kind": self.kind,
270
+ "version_id": version_id,
271
+ "version_manifest_hash": manifest["manifest_hash"],
272
+ "items_sha256": self.items_hash,
273
+ "annotations_sha256": manifest["annotations_sha256"],
274
+ "selected_at": datetime.now(timezone.utc).isoformat(),
275
+ }
276
+ selection = {**without_hash, "selection_hash": content_hash(without_hash)}
277
+ output_path.parent.mkdir(parents=True, exist_ok=True)
278
+ _write_atomic(
279
+ output_path, (json.dumps(selection, indent=2, sort_keys=True) + "\n").encode()
280
+ )
281
+ return selection
282
+
283
+ def _selection(self) -> Mapping[str, Any] | None:
284
+ path = self.selection_path
285
+ if path.is_symlink() or not path.is_file():
286
+ return None
287
+ value = _read_json(path)
288
+ expected = value.get("selection_hash")
289
+ unhashed = {key: item for key, item in value.items() if key != "selection_hash"}
290
+ if (
291
+ value.get("schema_version") != 1
292
+ or value.get("protocol") != ANNOTATION_SELECTION_PROTOCOL
293
+ or value.get("kind") != self.kind
294
+ or value.get("items_sha256") != self.items_hash
295
+ or expected != content_hash(unhashed)
296
+ ):
297
+ raise AnnotationStoreError("annotation selection receipt is invalid")
298
+ manifest = self._manifest(str(value.get("version_id", "")))
299
+ annotations_path = self.root / manifest["version_id"] / "annotations.jsonl"
300
+ if (
301
+ manifest["status"] != "complete"
302
+ or value.get("version_manifest_hash") != manifest["manifest_hash"]
303
+ or value.get("annotations_sha256") != manifest["annotations_sha256"]
304
+ or annotations_path.is_symlink()
305
+ or not annotations_path.is_file()
306
+ or _sha256(annotations_path) != manifest["annotations_sha256"]
307
+ ):
308
+ raise AnnotationStoreError("selected annotation version is unavailable or modified")
309
+ return value
310
+
311
+ def _manifest(self, version_id: str) -> Mapping[str, Any]:
312
+ version_id = _text(version_id, label="version_id")
313
+ if not version_id.startswith(f"{self.kind}-v") or not version_id[-3:].isdigit():
314
+ raise AnnotationStoreError("annotation version_id is invalid")
315
+ path = self.root / version_id / "manifest.json"
316
+ if path.is_symlink() or not path.is_file():
317
+ raise AnnotationStoreError("annotation version does not exist")
318
+ manifest = _read_json(path)
319
+ _validate_manifest(manifest, kind=self.kind, items_hash=self.items_hash)
320
+ return manifest
321
+
322
+ def _annotations(self, version_id: str) -> list[dict[str, Any]]:
323
+ path = self.root / version_id / "annotations.jsonl"
324
+ if path.is_symlink() or not path.is_file():
325
+ raise AnnotationStoreError("annotation version data is unavailable")
326
+ rows = []
327
+ for line_number, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
328
+ if not line.strip():
329
+ continue
330
+ value = json.loads(line)
331
+ if not isinstance(value, Mapping) or value.get("version_id") != version_id:
332
+ raise AnnotationStoreError(f"invalid annotation row at line {line_number}")
333
+ expected = value.get("annotation_hash")
334
+ unhashed = {key: item for key, item in value.items() if key != "annotation_hash"}
335
+ if expected != content_hash(unhashed):
336
+ raise AnnotationStoreError(f"annotation hash mismatch at line {line_number}")
337
+ rows.append(dict(value))
338
+ if len({row["item_id"] for row in rows}) != len(rows):
339
+ raise AnnotationStoreError("annotation version contains duplicate items")
340
+ return rows
341
+
342
+ @staticmethod
343
+ def _updated_manifest(manifest: Mapping[str, Any], **changes: Any) -> dict[str, Any]:
344
+ value = {key: item for key, item in manifest.items() if key != "manifest_hash"}
345
+ value.update(changes)
346
+ return {**value, "manifest_hash": content_hash(value)}
347
+
348
+
349
+ def _load_items(path: Path) -> list[dict[str, Any]]:
350
+ rows = []
351
+ for line_number, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
352
+ if not line.strip():
353
+ continue
354
+ value = json.loads(line)
355
+ if not isinstance(value, Mapping):
356
+ raise AnnotationStoreError(f"annotation item {line_number} must be an object")
357
+ item_id = value.get("audit_item_id", value.get("item_id"))
358
+ item_id = _text(item_id, label=f"annotation item {line_number} ID")
359
+ rows.append({"item_id": item_id, **dict(value)})
360
+ if not rows or len({row["item_id"] for row in rows}) != len(rows):
361
+ raise AnnotationStoreError("annotation items must be non-empty and unique")
362
+ return rows
363
+
364
+
365
+ def _validate_manifest(value: Mapping[str, Any], *, kind: str, items_hash: str) -> None:
366
+ expected = value.get("manifest_hash")
367
+ unhashed = {key: item for key, item in value.items() if key != "manifest_hash"}
368
+ if (
369
+ value.get("schema_version") != 1
370
+ or value.get("protocol") != ANNOTATION_VERSION_PROTOCOL
371
+ or value.get("kind") != kind
372
+ or value.get("items_sha256") != items_hash
373
+ or value.get("status") not in {"in_progress", "complete"}
374
+ or expected != content_hash(unhashed)
375
+ ):
376
+ raise AnnotationStoreError("annotation version manifest is invalid")
377
+
378
+
379
+ def _public_manifest(value: Mapping[str, Any]) -> dict[str, Any]:
380
+ return {
381
+ key: value[key]
382
+ for key in (
383
+ "version_id",
384
+ "kind",
385
+ "annotator_id",
386
+ "item_count",
387
+ "annotation_count",
388
+ "status",
389
+ "created_at",
390
+ "completed_at",
391
+ "supersedes_completed_version",
392
+ "manifest_hash",
393
+ )
394
+ }
395
+
396
+
397
+ def _write_atomic(path: Path, data: bytes | Mapping[str, Any]) -> None:
398
+ if isinstance(data, Mapping):
399
+ data = (json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True) + "\n").encode()
400
+ descriptor, temporary = tempfile.mkstemp(prefix=".partial-", dir=path.parent)
401
+ try:
402
+ with os.fdopen(descriptor, "wb") as handle:
403
+ handle.write(data)
404
+ handle.flush()
405
+ os.fsync(handle.fileno())
406
+ os.replace(temporary, path)
407
+ finally:
408
+ if os.path.exists(temporary):
409
+ os.unlink(temporary)
410
+
411
+
412
+ def _jsonl_bytes(rows: Sequence[Mapping[str, Any]]) -> bytes:
413
+ return "".join(canonical_json(row) + "\n" for row in rows).encode()
414
+
415
+
416
+ def _sha256(path: Path) -> str:
417
+ digest = hashlib.sha256()
418
+ with path.open("rb") as handle:
419
+ for block in iter(lambda: handle.read(1024 * 1024), b""):
420
+ digest.update(block)
421
+ return digest.hexdigest()
422
+
423
+
424
+ def _read_json(path: Path) -> Mapping[str, Any]:
425
+ value = json.loads(path.read_text(encoding="utf-8"))
426
+ if not isinstance(value, Mapping):
427
+ raise AnnotationStoreError("annotation manifest must be an object")
428
+ return value
429
+
430
+
431
+ def _text(value: Any, *, label: str) -> str:
432
+ if not isinstance(value, str) or not value.strip():
433
+ raise AnnotationStoreError(f"{label} must be a non-empty string")
434
+ return value.strip()
435
+
436
+
437
+ __all__ = [
438
+ "ANNOTATION_KINDS",
439
+ "ANNOTATION_SELECTION_PROTOCOL",
440
+ "ANNOTATION_VERSION_PROTOCOL",
441
+ "AnnotationStore",
442
+ "AnnotationStoreError",
443
+ "validate_annotation_selection",
444
+ ]