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,1766 @@
1
+ #!/usr/bin/env python3
2
+ """Pinned, user-mounted InfoCQR teacher/cache worker.
3
+
4
+ The driver never vendors InfoCQR. It verifies a caller-mounted checkout and
5
+ then either (a) calls the exact official ``generate_rewrite`` function through
6
+ a bounded OpenAI-compatible seam, or (b) replays one checksum-locked official
7
+ author JSON/JSONL artifact. The unreleased T5 student is represented by a fail-closed
8
+ checkpoint gate, not by substitute weights.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import ast
15
+ import hashlib
16
+ import importlib.util
17
+ import json
18
+ import math
19
+ import os
20
+ import re
21
+ import subprocess
22
+ import sys
23
+ import urllib.error
24
+ import urllib.parse
25
+ import urllib.request
26
+ from collections.abc import Mapping, Sequence
27
+ from dataclasses import dataclass
28
+ from pathlib import Path, PurePosixPath
29
+ from types import ModuleType, SimpleNamespace
30
+ from typing import Any, Protocol, TextIO
31
+
32
+ sys.dont_write_bytecode = True
33
+
34
+ UPSTREAM_COMMIT = "2953c461aa0c6817b1b7656dbd5168050227b31d"
35
+ METHOD_ID = "infocqr"
36
+ PROTOCOL_VERSION = "agentinputlab.infocqr.v1"
37
+ MANIFEST_SCHEMA = "agentinputlab.infocqr.compatibility.v1"
38
+ DEFAULT_MANIFEST = Path(__file__).with_name("compatibility_manifest.json")
39
+ MAX_REQUEST_BYTES = 4 * 1024 * 1024
40
+ MAX_RESPONSE_BYTES = 4 * 1024 * 1024
41
+ MAX_CACHE_BYTES = 1024 * 1024 * 1024
42
+ MAX_CACHE_RECORDS = 1_000_000
43
+ MAX_TEXT_CHARS = 1_000_000
44
+ OFFICIAL_MODEL_NAME = "gpt-3.5-turbo"
45
+ OFFICIAL_MAX_TOKENS = 2560
46
+ POSTPROCESS_PATH = "post_processing.py"
47
+ POSTPROCESS_SOURCE_SHA256 = "7201ceaeb16beaaf3af874faf083ce4f64dd630636a2e302edf398cc4da8d3dd"
48
+ FUSE_PATH = "fuse_rewrite.py"
49
+ T5_TEST_PATH = "T5QR/T5test.py"
50
+ T5_TRAIN_PATH = "T5QR/T5train.py"
51
+ _HASH_RE = re.compile(r"[0-9a-f]{64}")
52
+ _COMMIT_RE = re.compile(r"[0-9a-f]{40}")
53
+ _ENV_NAME_RE = re.compile(r"[A-Z_][A-Z0-9_]*")
54
+ _PROFILES = frozenset({"rw_zsl", "rw_fsl", "t5_edit", "self_edit"})
55
+ _ROOT_FIELDS = frozenset(
56
+ {
57
+ "method_id",
58
+ "release_id",
59
+ "upstream_commit",
60
+ "state_hash",
61
+ "payload",
62
+ "dependency_fingerprints",
63
+ "minimum_reservation",
64
+ "protocol_version",
65
+ "request_id",
66
+ }
67
+ )
68
+ _PAYLOAD_FIELDS = frozenset(
69
+ {
70
+ "operation",
71
+ "task_id",
72
+ "dataset_id",
73
+ "dataset_revision",
74
+ "split",
75
+ "conversation_source",
76
+ "conversation_no",
77
+ "turn_no",
78
+ "query",
79
+ "new_context",
80
+ "prompt_profile",
81
+ "prompt_source_sha256",
82
+ "cache_artifact_id",
83
+ "cache_artifact_sha256",
84
+ "allow_first_turn_truth_rewrite",
85
+ "source_license_acknowledged",
86
+ "retrieval_corpus_id",
87
+ "profile_kind",
88
+ "initial_rewrite",
89
+ "initial_rewrite_source_sha256",
90
+ "controls",
91
+ "seed",
92
+ }
93
+ )
94
+ _CONTROL_FIELDS = frozenset({"max_model_calls", "max_tokens", "max_cost_usd"})
95
+ _RELEASES = {
96
+ "rewrite.infocqr.cached_rw_zsl": ("cached_replay", "rw_zsl"),
97
+ "rewrite.infocqr.cached_rw_fsl": ("cached_replay", "rw_fsl"),
98
+ "rewrite.infocqr.cached_edit": ("cached_replay", "t5_edit"),
99
+ "rewrite.infocqr.live_teacher_external": ("live_teacher", "*"),
100
+ "rewrite.infocqr.common_support_rw_zsl": ("live_teacher", "rw_zsl"),
101
+ "rewrite.infocqr.t5_student_external": ("t5_student", "t5_student"),
102
+ }
103
+
104
+
105
+ class DriverError(RuntimeError):
106
+ """Expected, secret-free worker failure."""
107
+
108
+ def __init__(
109
+ self,
110
+ code: str,
111
+ message: str,
112
+ *,
113
+ consumed: bool = False,
114
+ usage: Mapping[str, int | float] | None = None,
115
+ ) -> None:
116
+ super().__init__(message)
117
+ self.code = code
118
+ self.consumed = consumed
119
+ self.usage = dict(usage) if usage is not None else None
120
+
121
+
122
+ @dataclass(frozen=True, slots=True)
123
+ class CompatibilityPolicy:
124
+ commit: str
125
+ license_status: str
126
+ license_file_present: bool
127
+ license_evidence_path: str
128
+ license_evidence_sha256: str
129
+ require_clean_checkout: bool
130
+ source_hashes: Mapping[str, str]
131
+ prompt_profiles: Mapping[str, Mapping[str, str]]
132
+ known_caches: Mapping[str, Mapping[str, str]]
133
+
134
+ @classmethod
135
+ def from_mapping(cls, value: Mapping[str, Any]) -> CompatibilityPolicy:
136
+ if value.get("schema_version") != MANIFEST_SCHEMA:
137
+ raise DriverError("INVALID_MANIFEST", "InfoCQR manifest schema mismatch")
138
+ upstream = _mapping(value.get("upstream"), "manifest upstream")
139
+ if upstream.get("commit") != UPSTREAM_COMMIT:
140
+ raise DriverError("INVALID_MANIFEST", "manifest commit is not approved")
141
+ if upstream.get("license_spdx") != "NOASSERTION":
142
+ raise DriverError("INVALID_MANIFEST", "InfoCQR license must remain NOASSERTION")
143
+ if upstream.get("license_file_present") is not False:
144
+ raise DriverError("INVALID_MANIFEST", "manifest must record absent license file")
145
+ clean = upstream.get("require_clean_checkout")
146
+ if not isinstance(clean, bool):
147
+ raise DriverError("INVALID_MANIFEST", "clean-checkout flag must be boolean")
148
+
149
+ source_files = _mapping(value.get("source_files"), "manifest source_files")
150
+ hashes = {
151
+ _safe_relative_path(path, "manifest source path"): _hash(
152
+ digest, f"manifest hash for {path}"
153
+ )
154
+ for path, digest in source_files.items()
155
+ }
156
+ required = {
157
+ "README.md",
158
+ "requirements.txt",
159
+ "rewrite_chatgpt_zsl.py",
160
+ "rewrite_chatgpt_inctx.py",
161
+ "rewrite_chatgpt_editor.py",
162
+ "rewrite_chatgpt_self_editor.py",
163
+ POSTPROCESS_PATH,
164
+ FUSE_PATH,
165
+ "dataset_cleaning.py",
166
+ T5_TEST_PATH,
167
+ T5_TRAIN_PATH,
168
+ }
169
+ if not required <= set(hashes):
170
+ raise DriverError("INVALID_MANIFEST", "manifest omits required InfoCQR sources")
171
+
172
+ raw_profiles = _mapping(value.get("prompt_profiles"), "manifest prompt_profiles")
173
+ if set(raw_profiles) != _PROFILES:
174
+ raise DriverError("INVALID_MANIFEST", "manifest prompt profile set changed")
175
+ profiles: dict[str, Mapping[str, str]] = {}
176
+ for profile, raw_item in raw_profiles.items():
177
+ item = _mapping(raw_item, f"prompt profile {profile}")
178
+ _exact_keys(
179
+ item,
180
+ {"source_path", "source_sha256", "official_function"},
181
+ "prompt profile",
182
+ )
183
+ path = _safe_relative_path(item["source_path"], "prompt source path")
184
+ digest = _hash(item["source_sha256"], "prompt source hash")
185
+ if hashes.get(path) != digest or item["official_function"] != "generate_rewrite":
186
+ raise DriverError("INVALID_MANIFEST", "prompt profile identity mismatch")
187
+ profiles[profile] = {
188
+ "source_path": path,
189
+ "source_sha256": digest,
190
+ "official_function": "generate_rewrite",
191
+ }
192
+
193
+ raw_caches = _mapping(value.get("known_author_caches"), "known author caches")
194
+ caches: dict[str, Mapping[str, str]] = {}
195
+ for cache_id, raw_item in raw_caches.items():
196
+ item = _mapping(raw_item, f"known cache {cache_id}")
197
+ _exact_keys(item, {"path", "sha256", "profile", "split"}, "known cache")
198
+ profile = _text(item["profile"], "known cache profile")
199
+ if profile not in _PROFILES:
200
+ raise DriverError("INVALID_MANIFEST", "known cache profile is unsupported")
201
+ caches[_text(cache_id, "known cache id")] = {
202
+ "path": _safe_relative_path(item["path"], "known cache path"),
203
+ "sha256": _hash(item["sha256"], "known cache hash"),
204
+ "profile": profile,
205
+ "split": _text(item["split"], "known cache split"),
206
+ }
207
+
208
+ execution = _mapping(value.get("execution"), "manifest execution")
209
+ if (
210
+ execution.get("vendored_upstream_source") is not False
211
+ or execution.get("t5_student_runtime_enabled") is not False
212
+ or execution.get("released_t5_checkpoint_present") is not False
213
+ or execution.get("paper_result_parity_claimed") is not False
214
+ or execution.get("common_support_profile") != "controlled_adapter_visible_dialogue_only"
215
+ or execution.get("post_processing_compatibility_hash") != hashes[POSTPROCESS_PATH]
216
+ ):
217
+ raise DriverError("INVALID_MANIFEST", "execution safety declarations changed")
218
+ evidence = _safe_relative_path(
219
+ upstream.get("license_evidence_path"), "license evidence path"
220
+ )
221
+ return cls(
222
+ commit=UPSTREAM_COMMIT,
223
+ license_status="NOASSERTION",
224
+ license_file_present=False,
225
+ license_evidence_path=evidence,
226
+ license_evidence_sha256=_hash(
227
+ upstream.get("license_evidence_sha256"), "license evidence hash"
228
+ ),
229
+ require_clean_checkout=clean,
230
+ source_hashes=hashes,
231
+ prompt_profiles=profiles,
232
+ known_caches=caches,
233
+ )
234
+
235
+
236
+ @dataclass(frozen=True, slots=True)
237
+ class BackendConfig:
238
+ base_url: str
239
+ api_key_env: str
240
+ model: str
241
+ fingerprint: Mapping[str, Any]
242
+ extra_body: Mapping[str, Any]
243
+ timeout_seconds: float
244
+ max_input_tokens_per_call: int
245
+ max_output_tokens: int
246
+ temperature: float
247
+ input_cost_per_million: float
248
+ output_cost_per_million: float
249
+
250
+ @classmethod
251
+ def from_json(cls, raw: str) -> BackendConfig:
252
+ value = _mapping(_loads_strict_json(raw), "backend configuration")
253
+ _exact_keys(
254
+ value,
255
+ {
256
+ "base_url",
257
+ "api_key_env",
258
+ "model",
259
+ "fingerprint",
260
+ "extra_body",
261
+ "timeout_seconds",
262
+ "max_input_tokens_per_call",
263
+ "max_output_tokens",
264
+ "temperature",
265
+ "input_cost_per_million",
266
+ "output_cost_per_million",
267
+ },
268
+ "backend configuration",
269
+ )
270
+ model = _text(value["model"], "backend model")
271
+ fingerprint = dict(_mapping(value["fingerprint"], "backend fingerprint"))
272
+ fingerprint_model = fingerprint.get("model_id", fingerprint.get("model"))
273
+ if fingerprint_model is None:
274
+ nested = fingerprint.get("backend")
275
+ if isinstance(nested, Mapping):
276
+ fingerprint_model = nested.get("model_id", nested.get("model"))
277
+ if not fingerprint or fingerprint_model != model:
278
+ raise DriverError(
279
+ "INVALID_BACKEND_CONFIG",
280
+ "backend fingerprint must bind the exact model",
281
+ )
282
+ extra_body = dict(_mapping(value["extra_body"], "backend extra_body"))
283
+ reserved = {"model", "messages", "temperature", "seed", "max_tokens"}
284
+ if reserved & set(extra_body):
285
+ raise DriverError(
286
+ "INVALID_BACKEND_CONFIG", "backend extra_body overrides reserved fields"
287
+ )
288
+ _canonical_json(extra_body)
289
+ api_key_env = _text(value["api_key_env"], "backend api_key_env")
290
+ if _ENV_NAME_RE.fullmatch(api_key_env) is None:
291
+ raise DriverError("INVALID_BACKEND_CONFIG", "api_key_env is invalid")
292
+ temperature = _nonnegative_float(value["temperature"], "backend temperature")
293
+ if temperature > 2:
294
+ raise DriverError("INVALID_BACKEND_CONFIG", "backend temperature exceeds 2")
295
+ return cls(
296
+ base_url=_validate_base_url(_text(value["base_url"], "backend base_url")),
297
+ api_key_env=api_key_env,
298
+ model=model,
299
+ fingerprint=fingerprint,
300
+ extra_body=extra_body,
301
+ timeout_seconds=_positive_float(value["timeout_seconds"], "backend timeout"),
302
+ max_input_tokens_per_call=_positive_int(
303
+ value["max_input_tokens_per_call"],
304
+ "backend max_input_tokens_per_call",
305
+ ),
306
+ max_output_tokens=_positive_int(
307
+ value["max_output_tokens"], "backend max_output_tokens"
308
+ ),
309
+ temperature=temperature,
310
+ input_cost_per_million=_nonnegative_float(
311
+ value["input_cost_per_million"], "backend input price"
312
+ ),
313
+ output_cost_per_million=_nonnegative_float(
314
+ value["output_cost_per_million"], "backend output price"
315
+ ),
316
+ )
317
+
318
+
319
+ @dataclass(frozen=True, slots=True)
320
+ class CompletionResult:
321
+ text: str
322
+ input_tokens: int
323
+ output_tokens: int
324
+
325
+
326
+ class CompletionBackend(Protocol):
327
+ def fingerprint(self) -> Mapping[str, Any]: ...
328
+
329
+ def complete(
330
+ self,
331
+ *,
332
+ messages: Sequence[Mapping[str, str]],
333
+ seed: int,
334
+ temperature: float,
335
+ max_output_tokens: int,
336
+ ) -> CompletionResult: ...
337
+
338
+
339
+ class OpenAICompatibleBackend:
340
+ def __init__(self, config: BackendConfig) -> None:
341
+ self.config = config
342
+
343
+ def fingerprint(self) -> Mapping[str, Any]:
344
+ return self.config.fingerprint
345
+
346
+ def complete(
347
+ self,
348
+ *,
349
+ messages: Sequence[Mapping[str, str]],
350
+ seed: int,
351
+ temperature: float,
352
+ max_output_tokens: int,
353
+ ) -> CompletionResult:
354
+ key = os.environ.get(self.config.api_key_env)
355
+ if not key:
356
+ raise DriverError("BACKEND_CREDENTIAL_UNAVAILABLE", "backend credential unavailable")
357
+ body = {
358
+ "model": self.config.model,
359
+ "messages": list(messages),
360
+ "temperature": temperature,
361
+ "seed": seed,
362
+ "max_tokens": max_output_tokens,
363
+ }
364
+ body.update(self.config.extra_body)
365
+ request = urllib.request.Request(
366
+ f"{self.config.base_url}/chat/completions",
367
+ data=_canonical_json(body).encode("utf-8"),
368
+ headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"},
369
+ method="POST",
370
+ )
371
+ try:
372
+ with urllib.request.urlopen(request, timeout=self.config.timeout_seconds) as response:
373
+ raw = response.read(MAX_RESPONSE_BYTES + 1)
374
+ except (OSError, urllib.error.HTTPError, urllib.error.URLError) as exc:
375
+ raise DriverError(
376
+ "BACKEND_CALL_FAILED",
377
+ "backend completion request failed",
378
+ consumed=True,
379
+ ) from exc
380
+ if len(raw) > MAX_RESPONSE_BYTES:
381
+ raise DriverError(
382
+ "BACKEND_RESPONSE_TOO_LARGE",
383
+ "backend response exceeded limit",
384
+ consumed=True,
385
+ )
386
+ try:
387
+ root = _mapping(_loads_strict_json(raw.decode("utf-8")), "backend response")
388
+ if root.get("model") not in {None, self.config.model}:
389
+ raise DriverError("BACKEND_IDENTITY_MISMATCH", "provider returned another model")
390
+ choices = root.get("choices")
391
+ if (
392
+ not isinstance(choices, Sequence)
393
+ or isinstance(choices, (str, bytes))
394
+ or len(choices) != 1
395
+ ):
396
+ raise DriverError("BACKEND_OUTPUT_INVALID", "backend must return one choice")
397
+ choice = _mapping(choices[0], "backend choice")
398
+ message = _mapping(choice.get("message"), "backend message")
399
+ text = message.get("content")
400
+ if not isinstance(text, str):
401
+ raise DriverError("BACKEND_OUTPUT_INVALID", "backend content must be text")
402
+ usage = _mapping(root.get("usage"), "backend usage")
403
+ return CompletionResult(
404
+ text=text,
405
+ input_tokens=_nonnegative_int(usage.get("prompt_tokens"), "prompt_tokens"),
406
+ output_tokens=_nonnegative_int(usage.get("completion_tokens"), "completion_tokens"),
407
+ )
408
+ except (DriverError, UnicodeDecodeError) as exc:
409
+ if isinstance(exc, DriverError):
410
+ exc.consumed = True
411
+ raise
412
+ raise DriverError(
413
+ "BACKEND_OUTPUT_INVALID",
414
+ "backend response must be UTF-8 JSON",
415
+ consumed=True,
416
+ ) from exc
417
+
418
+
419
+ @dataclass(frozen=True, slots=True)
420
+ class Controls:
421
+ max_model_calls: int
422
+ max_tokens: int
423
+ max_cost_usd: float
424
+
425
+
426
+ @dataclass(frozen=True, slots=True)
427
+ class ValidatedRequest:
428
+ request_id: str
429
+ release_id: str
430
+ operation: str
431
+ task_id: str
432
+ dataset_id: str
433
+ dataset_revision: str
434
+ split: str
435
+ conversation_source: str
436
+ conversation_no: int
437
+ turn_no: int
438
+ query: str
439
+ new_context: tuple[str, ...]
440
+ prompt_profile: str
441
+ prompt_source_sha256: str
442
+ cache_artifact_id: str
443
+ cache_artifact_sha256: str
444
+ allow_first_turn_truth_rewrite: bool
445
+ retrieval_corpus_id: str
446
+ profile_kind: str
447
+ initial_rewrite: str
448
+ initial_rewrite_source_sha256: str
449
+ controls: Controls
450
+ seed: int
451
+ backend_fingerprint: Mapping[str, Any]
452
+ retriever_fingerprint: Mapping[str, Any]
453
+
454
+
455
+ class UsageTracker:
456
+ def __init__(self, controls: Controls, config: BackendConfig) -> None:
457
+ self.controls = controls
458
+ self.config = config
459
+ self.model_calls = 0
460
+ self.input_tokens = 0
461
+ self.output_tokens = 0
462
+ self.cost_usd = 0.0
463
+ self.stages: list[dict[str, Any]] = []
464
+
465
+ def complete(
466
+ self,
467
+ backend: CompletionBackend,
468
+ *,
469
+ stage: str,
470
+ messages: Sequence[Mapping[str, str]],
471
+ seed: int,
472
+ official_max_output_tokens: int,
473
+ ) -> CompletionResult:
474
+ if self.model_calls >= self.controls.max_model_calls:
475
+ raise DriverError("MODEL_CALL_BUDGET_EXCEEDED", "InfoCQR max_model_calls exhausted")
476
+ output_ceiling = min(
477
+ official_max_output_tokens,
478
+ self.config.max_output_tokens,
479
+ )
480
+ token_ceiling = self.config.max_input_tokens_per_call + output_ceiling
481
+ remaining_tokens = self.controls.max_tokens - self.input_tokens - self.output_tokens
482
+ if token_ceiling > remaining_tokens:
483
+ raise DriverError(
484
+ "TOKEN_BUDGET_EXCEEDED",
485
+ "InfoCQR attested input/output ceiling exceeds the remaining token budget",
486
+ )
487
+ call_cost_ceiling = (
488
+ self.config.max_input_tokens_per_call * self.config.input_cost_per_million
489
+ + output_ceiling * self.config.output_cost_per_million
490
+ ) / 1_000_000
491
+ if self.cost_usd + call_cost_ceiling > self.controls.max_cost_usd:
492
+ raise DriverError(
493
+ "COST_BUDGET_EXCEEDED",
494
+ "InfoCQR attested provider-price ceiling exceeds the remaining cost budget",
495
+ )
496
+ self.model_calls += 1
497
+ try:
498
+ result = backend.complete(
499
+ messages=messages,
500
+ seed=seed,
501
+ temperature=self.config.temperature,
502
+ max_output_tokens=output_ceiling,
503
+ )
504
+ except DriverError as exc:
505
+ if exc.code == "BACKEND_CREDENTIAL_UNAVAILABLE" and not exc.consumed:
506
+ self.model_calls -= 1
507
+ else:
508
+ exc.consumed = True
509
+ exc.usage = self.as_dict()
510
+ raise
511
+ if not isinstance(result, CompletionResult):
512
+ raise DriverError(
513
+ "BACKEND_OUTPUT_INVALID",
514
+ "backend returned invalid completion",
515
+ consumed=True,
516
+ usage=self.as_dict(),
517
+ )
518
+ input_tokens = _nonnegative_int(result.input_tokens, "completion input_tokens")
519
+ output_tokens = _nonnegative_int(result.output_tokens, "completion output_tokens")
520
+ self.input_tokens += input_tokens
521
+ self.output_tokens += output_tokens
522
+ self.cost_usd += (
523
+ input_tokens * self.config.input_cost_per_million
524
+ + output_tokens * self.config.output_cost_per_million
525
+ ) / 1_000_000
526
+ if input_tokens > self.config.max_input_tokens_per_call or output_tokens > output_ceiling:
527
+ raise DriverError(
528
+ "BACKEND_USAGE_ATTESTATION_EXCEEDED",
529
+ "InfoCQR provider usage exceeded the startup token attestation",
530
+ consumed=True,
531
+ usage=self.as_dict(),
532
+ )
533
+ if self.input_tokens + self.output_tokens > self.controls.max_tokens:
534
+ raise DriverError(
535
+ "TOKEN_BUDGET_EXCEEDED",
536
+ "InfoCQR max_tokens exceeded",
537
+ consumed=True,
538
+ usage=self.as_dict(),
539
+ )
540
+ if self.cost_usd > self.controls.max_cost_usd:
541
+ raise DriverError(
542
+ "COST_BUDGET_EXCEEDED",
543
+ "InfoCQR max_cost_usd exceeded",
544
+ consumed=True,
545
+ usage=self.as_dict(),
546
+ )
547
+ self.stages.append(
548
+ {
549
+ "index": len(self.stages),
550
+ "stage": stage,
551
+ "seed": seed,
552
+ "input_tokens": input_tokens,
553
+ "output_tokens": output_tokens,
554
+ "response_sha256": _sha256_bytes(result.text.encode("utf-8")),
555
+ }
556
+ )
557
+ return result
558
+
559
+ def as_dict(self) -> dict[str, int | float]:
560
+ return {
561
+ "model_calls": self.model_calls,
562
+ "retrieval_calls": 0,
563
+ "input_tokens": self.input_tokens,
564
+ "output_tokens": self.output_tokens,
565
+ "cost_usd": self.cost_usd,
566
+ }
567
+
568
+
569
+ class _LegacyChatCompletion:
570
+ """Map the official pre-v1 OpenAI call to one pinned backend."""
571
+
572
+ def __init__(
573
+ self,
574
+ backend: CompletionBackend,
575
+ tracker: UsageTracker,
576
+ *,
577
+ stage: str,
578
+ seed: int,
579
+ ) -> None:
580
+ self.backend = backend
581
+ self.tracker = tracker
582
+ self.stage = stage
583
+ self.seed = seed
584
+ self.fatal_error: DriverError | None = None
585
+ self.call_count = 0
586
+
587
+ def create(self, **kwargs: Any) -> Mapping[str, Any]:
588
+ if self.fatal_error is not None:
589
+ raise self.fatal_error
590
+ if set(kwargs) != {"model", "messages", "temperature", "max_tokens", "n"}:
591
+ raise DriverError("UPSTREAM_API_MISMATCH", "official ChatCompletion shape changed")
592
+ if (
593
+ kwargs["model"] != OFFICIAL_MODEL_NAME
594
+ or kwargs["temperature"] != 0
595
+ or kwargs["max_tokens"] != OFFICIAL_MAX_TOKENS
596
+ or kwargs["n"] != 1
597
+ ):
598
+ raise DriverError("UPSTREAM_API_MISMATCH", "official generation controls changed")
599
+ messages = _messages(kwargs["messages"])
600
+ try:
601
+ result = self.tracker.complete(
602
+ self.backend,
603
+ stage=self.stage,
604
+ messages=messages,
605
+ seed=self.seed,
606
+ official_max_output_tokens=OFFICIAL_MAX_TOKENS,
607
+ )
608
+ except DriverError as exc:
609
+ self.fatal_error = exc
610
+ raise
611
+ self.call_count += 1
612
+ return {
613
+ "model": self.tracker.config.model,
614
+ "usage": {
615
+ "prompt_tokens": result.input_tokens,
616
+ "completion_tokens": result.output_tokens,
617
+ "total_tokens": result.input_tokens + result.output_tokens,
618
+ },
619
+ "choices": [
620
+ {
621
+ "message": {"role": "assistant", "content": result.text},
622
+ "finish_reason": "stop",
623
+ "index": 0,
624
+ }
625
+ ],
626
+ }
627
+
628
+ def raise_fatal(self) -> None:
629
+ if self.fatal_error is not None:
630
+ raise self.fatal_error
631
+
632
+
633
+ @dataclass(frozen=True, slots=True)
634
+ class MountedCache:
635
+ path: Path
636
+ artifact_id: str
637
+ sha256: str
638
+ profile: str
639
+ split: str
640
+ artifact_format: str
641
+ records: Mapping[tuple[str, int, int, str, str], Mapping[str, Any]]
642
+
643
+ @classmethod
644
+ def load(
645
+ cls,
646
+ path: Path,
647
+ *,
648
+ artifact_id: str,
649
+ expected_sha256: str,
650
+ profile: str,
651
+ split: str,
652
+ ) -> MountedCache:
653
+ resolved = path.expanduser().resolve(strict=True)
654
+ if not resolved.is_file() or resolved.is_symlink():
655
+ raise DriverError("CACHE_ARTIFACT_UNAVAILABLE", "cache artifact is unavailable")
656
+ if resolved.stat().st_size > MAX_CACHE_BYTES:
657
+ raise DriverError("CACHE_ARTIFACT_TOO_LARGE", "cache artifact exceeds size limit")
658
+ digest = _sha256_file(resolved)
659
+ if digest != _hash(expected_sha256, "cache artifact hash"):
660
+ raise DriverError("CACHE_CHECKSUM_MISMATCH", "cache artifact checksum mismatch")
661
+ if profile not in _PROFILES:
662
+ raise DriverError("CACHE_SCHEMA_INVALID", "cache profile is unsupported")
663
+ records: dict[tuple[str, int, int, str, str], Mapping[str, Any]] = {}
664
+
665
+ def add_record(value: Any, record_no: int) -> None:
666
+ if len(records) >= MAX_CACHE_RECORDS:
667
+ raise DriverError("CACHE_ARTIFACT_TOO_LARGE", "cache record count exceeds limit")
668
+ record = _validate_author_cache_record(
669
+ _mapping(value, f"cache record {record_no}"), profile, record_no
670
+ )
671
+ key = (
672
+ record["conversation_source"],
673
+ record["conversation_no"],
674
+ record["turn_no"],
675
+ record["query"],
676
+ _canonical_hash(record["new_context"]),
677
+ )
678
+ if key not in records:
679
+ # Upstream appends some published artifacts and can repeat turns.
680
+ # Byte order is checksum-bound; the first occurrence is a stable,
681
+ # disclosed keyed view rather than a silent candidate merge.
682
+ records[key] = record
683
+
684
+ try:
685
+ with resolved.open("r", encoding="utf-8") as handle:
686
+ prefix = handle.read(4096)
687
+ first = next((character for character in prefix if not character.isspace()), "")
688
+ if first == "[":
689
+ artifact_format = "json_array"
690
+ value = _loads_strict_json(resolved.read_text(encoding="utf-8"))
691
+ if isinstance(value, (str, bytes)) or not isinstance(value, Sequence):
692
+ raise DriverError("CACHE_SCHEMA_INVALID", "cache JSON must contain an array")
693
+ for record_no, item in enumerate(value, start=1):
694
+ add_record(item, record_no)
695
+ else:
696
+ artifact_format = "jsonl"
697
+ with resolved.open("r", encoding="utf-8") as handle:
698
+ for line_no, raw in enumerate(handle, start=1):
699
+ if raw.strip():
700
+ add_record(_loads_strict_json(raw), line_no)
701
+ except UnicodeDecodeError as exc:
702
+ raise DriverError("CACHE_SCHEMA_INVALID", "cache must be UTF-8 JSON or JSONL") from exc
703
+ if not records:
704
+ raise DriverError("CACHE_SCHEMA_INVALID", "cache must contain records")
705
+ return cls(
706
+ path=resolved,
707
+ artifact_id=_text(artifact_id, "cache artifact id"),
708
+ sha256=digest,
709
+ profile=profile,
710
+ split=_text(split, "cache split"),
711
+ artifact_format=artifact_format,
712
+ records=records,
713
+ )
714
+
715
+
716
+ class InfoCQRRuntime:
717
+ def __init__(
718
+ self,
719
+ checkout: Path,
720
+ backend_config: BackendConfig | None = None,
721
+ backend: CompletionBackend | None = None,
722
+ *,
723
+ cache: MountedCache | None = None,
724
+ source_license_acknowledged: bool = False,
725
+ policy: CompatibilityPolicy | None = None,
726
+ ) -> None:
727
+ if source_license_acknowledged is not True:
728
+ raise DriverError(
729
+ "SOURCE_LICENSE_NOT_ACKNOWLEDGED",
730
+ "InfoCQR source is NOASSERTION and requires operator acknowledgement",
731
+ )
732
+ self.policy = policy or load_compatibility_policy()
733
+ self.checkout, self.checkout_identity_mode = verify_checkout(checkout, self.policy)
734
+ self.cache = cache
735
+ self.backend_config = backend_config
736
+ self.backend = backend
737
+ if (backend_config is None) != (backend is None):
738
+ raise DriverError(
739
+ "INVALID_BACKEND_CONFIG", "backend config and backend must be supplied together"
740
+ )
741
+ if (
742
+ backend_config is not None
743
+ and backend is not None
744
+ and _canonical_json(backend.fingerprint())
745
+ != _canonical_json(backend_config.fingerprint)
746
+ ):
747
+ raise DriverError("BACKEND_IDENTITY_MISMATCH", "backend differs from startup config")
748
+ self.generators = _load_official_generators(self.checkout, self.policy)
749
+ self.source_symbols = audit_source_symbols(self.checkout, self.policy)
750
+
751
+ def run(self, value: Mapping[str, Any]) -> dict[str, Any]:
752
+ request = validate_request(
753
+ value,
754
+ self.policy,
755
+ backend_config=self.backend_config,
756
+ mounted_cache=self.cache,
757
+ )
758
+ if request.operation == "t5_student":
759
+ raise DriverError(
760
+ "T5_CHECKPOINT_UNAVAILABLE",
761
+ "InfoCQR publishes a T5 training recipe but no released student checkpoint",
762
+ )
763
+ if request.operation == "cached_replay":
764
+ return self._run_cache(request)
765
+ return self._run_live(request)
766
+
767
+ def _run_cache(self, request: ValidatedRequest) -> dict[str, Any]:
768
+ cache = self.cache
769
+ if cache is None: # pragma: no cover - validated before dispatch
770
+ raise DriverError("CACHE_ARTIFACT_UNAVAILABLE", "cache is not mounted")
771
+ key = (
772
+ request.conversation_source,
773
+ request.conversation_no,
774
+ request.turn_no,
775
+ request.query,
776
+ _canonical_hash(request.new_context),
777
+ )
778
+ try:
779
+ record = cache.records[key]
780
+ except KeyError as exc:
781
+ raise DriverError("CACHE_RECORD_UNAVAILABLE", "cache has no requested turn") from exc
782
+ if record["query"] != request.query or tuple(record["new_context"]) != request.new_context:
783
+ raise DriverError("CACHE_RECORD_IDENTITY_MISMATCH", "cache conversation view mismatch")
784
+ first_turn_truth = request.turn_no == 1 and not request.new_context
785
+ if first_turn_truth and not request.allow_first_turn_truth_rewrite:
786
+ raise DriverError(
787
+ "GOLD_DERIVED_FIRST_TURN_BLOCKED",
788
+ "official first-turn cache copies Truth_rewrite and is disabled by policy",
789
+ )
790
+ candidate, historical_usage = _legacy_candidate(record["candidate"])
791
+ initial = ""
792
+ if request.prompt_profile in {"t5_edit", "self_edit"}:
793
+ initial, _ = _legacy_candidate(record["initial_rewrite"])
794
+ rewrite, postprocess_status = _official_postprocess_compat(
795
+ candidate,
796
+ question=request.query,
797
+ turn_no=request.turn_no,
798
+ editor=request.prompt_profile in {"t5_edit", "self_edit"},
799
+ initial_rewrite=initial,
800
+ )
801
+ return self._response(
802
+ request,
803
+ rewrite=rewrite,
804
+ raw_candidates=(candidate,),
805
+ initial_rewrite=initial,
806
+ postprocess_status=postprocess_status,
807
+ calls=(
808
+ "fuse_rewrite.record_extraction",
809
+ "post_processing.pinned_branch_reconstruction",
810
+ ),
811
+ execution_label="compatibility_replay",
812
+ usage={
813
+ "model_calls": 0,
814
+ "retrieval_calls": 0,
815
+ "input_tokens": 0,
816
+ "output_tokens": 0,
817
+ "cost_usd": 0.0,
818
+ },
819
+ usage_stages=(),
820
+ historical_usage=historical_usage,
821
+ )
822
+
823
+ def _run_live(self, request: ValidatedRequest) -> dict[str, Any]:
824
+ if self.backend_config is None or self.backend is None:
825
+ raise DriverError("BACKEND_UNAVAILABLE", "live teacher backend is not configured")
826
+ tracker = UsageTracker(request.controls, self.backend_config)
827
+ line: dict[str, Any] = {
828
+ "NewContext": list(request.new_context),
829
+ "Question": request.query,
830
+ }
831
+ raw_candidates: list[str] = []
832
+ official_calls: list[str] = []
833
+ initial = request.initial_rewrite
834
+
835
+ if request.prompt_profile in {"rw_zsl", "rw_fsl"}:
836
+ candidate = self._call_official(
837
+ request.prompt_profile,
838
+ line,
839
+ tracker,
840
+ stage=request.prompt_profile,
841
+ seed=request.seed,
842
+ )
843
+ raw_candidates.append(candidate)
844
+ official_calls.append(
845
+ f"{self.policy.prompt_profiles[request.prompt_profile]['source_path']}::generate_rewrite"
846
+ )
847
+ rewrite, status = _official_postprocess_compat(
848
+ candidate,
849
+ question=request.query,
850
+ turn_no=request.turn_no,
851
+ editor=False,
852
+ initial_rewrite="",
853
+ )
854
+ elif request.prompt_profile == "self_edit":
855
+ generated = self._call_official(
856
+ "rw_fsl",
857
+ line,
858
+ tracker,
859
+ stage="rw_fsl",
860
+ seed=request.seed,
861
+ )
862
+ raw_candidates.append(generated)
863
+ official_calls.append("rewrite_chatgpt_inctx.py::generate_rewrite")
864
+ initial, initial_status = _official_postprocess_compat(
865
+ generated,
866
+ question=request.query,
867
+ turn_no=request.turn_no,
868
+ editor=False,
869
+ initial_rewrite="",
870
+ )
871
+ line["GPT_rewrite"] = initial
872
+ edited = self._call_official(
873
+ "self_edit",
874
+ line,
875
+ tracker,
876
+ stage="self_edit",
877
+ seed=request.seed + 1,
878
+ )
879
+ raw_candidates.append(edited)
880
+ official_calls.append("rewrite_chatgpt_self_editor.py::generate_rewrite")
881
+ rewrite, edit_status = _official_postprocess_compat(
882
+ edited,
883
+ question=request.query,
884
+ turn_no=request.turn_no,
885
+ editor=True,
886
+ initial_rewrite=initial,
887
+ )
888
+ status = f"initial:{initial_status};edit:{edit_status}"
889
+ else:
890
+ line["T5_rewrite"] = initial
891
+ edited = self._call_official(
892
+ "t5_edit",
893
+ line,
894
+ tracker,
895
+ stage="t5_edit",
896
+ seed=request.seed,
897
+ )
898
+ raw_candidates.append(edited)
899
+ official_calls.append("rewrite_chatgpt_editor.py::generate_rewrite")
900
+ rewrite, status = _official_postprocess_compat(
901
+ edited,
902
+ question=request.query,
903
+ turn_no=request.turn_no,
904
+ editor=True,
905
+ initial_rewrite=initial,
906
+ )
907
+ return self._response(
908
+ request,
909
+ rewrite=rewrite,
910
+ raw_candidates=tuple(raw_candidates),
911
+ initial_rewrite=initial,
912
+ postprocess_status=status,
913
+ calls=tuple(official_calls),
914
+ execution_label="official_function_calls",
915
+ usage=tracker.as_dict(),
916
+ usage_stages=tuple(tracker.stages),
917
+ historical_usage={},
918
+ )
919
+
920
+ def _call_official(
921
+ self,
922
+ profile: str,
923
+ line: Mapping[str, Any],
924
+ tracker: UsageTracker,
925
+ *,
926
+ stage: str,
927
+ seed: int,
928
+ ) -> str:
929
+ module = self.generators[profile]
930
+ shim = _LegacyChatCompletion(self.backend, tracker, stage=stage, seed=seed)
931
+ module.openai = SimpleNamespace(ChatCompletion=shim)
932
+ module.time = SimpleNamespace(sleep=lambda _seconds: None)
933
+ result = module.generate_rewrite(dict(line))
934
+ shim.raise_fatal()
935
+ if shim.call_count != 1:
936
+ raise DriverError("UPSTREAM_API_MISMATCH", "official teacher call count changed")
937
+ text, _usage = _legacy_candidate(result)
938
+ if not text.strip():
939
+ raise DriverError("UPSTREAM_OUTPUT_INVALID", "official teacher returned empty text")
940
+ return text
941
+
942
+ def _response(
943
+ self,
944
+ request: ValidatedRequest,
945
+ *,
946
+ rewrite: str,
947
+ raw_candidates: Sequence[str],
948
+ initial_rewrite: str,
949
+ postprocess_status: str,
950
+ calls: Sequence[str],
951
+ execution_label: str,
952
+ usage: Mapping[str, int | float],
953
+ usage_stages: Sequence[Mapping[str, Any]],
954
+ historical_usage: Mapping[str, Any],
955
+ ) -> dict[str, Any]:
956
+ if not rewrite.strip():
957
+ raise DriverError("UPSTREAM_OUTPUT_INVALID", "InfoCQR produced empty rewrite")
958
+ cache_hash = self.cache.sha256 if self.cache is not None else ""
959
+ return {
960
+ "status": "ok",
961
+ "request_id": request.request_id,
962
+ "upstream_commit": UPSTREAM_COMMIT,
963
+ "protocol_version": PROTOCOL_VERSION,
964
+ "payload": {
965
+ "rewrite": rewrite.strip(),
966
+ "raw_candidates": list(raw_candidates),
967
+ "initial_rewrite": initial_rewrite,
968
+ "postprocess_status": postprocess_status,
969
+ "postprocess_source_sha256": POSTPROCESS_SOURCE_SHA256,
970
+ "prompt_profile": request.prompt_profile,
971
+ "prompt_source_sha256": request.prompt_source_sha256,
972
+ "operation": request.operation,
973
+ "dataset_id": request.dataset_id,
974
+ "dataset_revision": request.dataset_revision,
975
+ "split": request.split,
976
+ "conversation_source": request.conversation_source,
977
+ "conversation_no": request.conversation_no,
978
+ "turn_no": request.turn_no,
979
+ "conversation_view_hash": _canonical_hash(
980
+ {"query": request.query, "new_context": request.new_context}
981
+ ),
982
+ "retrieval_corpus_id": request.retrieval_corpus_id,
983
+ "cache_artifact_id": self.cache.artifact_id if self.cache else "",
984
+ "cache_artifact_sha256": cache_hash,
985
+ "cache_artifact_format": (
986
+ self.cache.artifact_format if self.cache is not None else ""
987
+ ),
988
+ "cache_duplicate_policy": (
989
+ f"first_occurrence_in_checksum_bound_{self.cache.artifact_format}"
990
+ if self.cache is not None
991
+ else ""
992
+ ),
993
+ "historical_usage": dict(historical_usage),
994
+ "usage_stages": list(usage_stages),
995
+ "execution_label": execution_label,
996
+ "official_calls": (
997
+ list(calls) if execution_label == "official_function_calls" else []
998
+ ),
999
+ "reconstructed_calls": (
1000
+ list(calls) if execution_label == "compatibility_replay" else []
1001
+ ),
1002
+ "official_requested_model": OFFICIAL_MODEL_NAME,
1003
+ "configured_teacher_model": (
1004
+ self.backend_config.model if self.backend_config is not None else ""
1005
+ ),
1006
+ "profile_kind": request.profile_kind,
1007
+ "source_license_id": "NOASSERTION",
1008
+ "source_license_acknowledged": True,
1009
+ "checkout_identity_mode": self.checkout_identity_mode,
1010
+ "vendored_upstream_source": False,
1011
+ "t5_student_checkpoint_used": False,
1012
+ "paper_result_parity_claimed": False,
1013
+ },
1014
+ "usage": dict(usage),
1015
+ }
1016
+
1017
+
1018
+ def load_compatibility_policy(path: Path = DEFAULT_MANIFEST) -> CompatibilityPolicy:
1019
+ try:
1020
+ raw = path.read_text(encoding="utf-8")
1021
+ except OSError as exc:
1022
+ raise DriverError("INVALID_MANIFEST", "InfoCQR manifest is unavailable") from exc
1023
+ return CompatibilityPolicy.from_mapping(
1024
+ _mapping(_loads_strict_json(raw), "compatibility manifest")
1025
+ )
1026
+
1027
+
1028
+ def verify_checkout(checkout: Path, policy: CompatibilityPolicy) -> tuple[Path, str]:
1029
+ root = checkout.expanduser().resolve(strict=True)
1030
+ if not root.is_dir() or root.is_symlink():
1031
+ raise DriverError("CHECKOUT_UNAVAILABLE", "InfoCQR checkout must be a real directory")
1032
+ for name in ("LICENSE", "LICENSE.txt", "COPYING", "NOTICE"):
1033
+ if (root / name).exists():
1034
+ raise DriverError(
1035
+ "LICENSE_STATE_MISMATCH", "pinned checkout unexpectedly contains a license file"
1036
+ )
1037
+ for relative, expected in policy.source_hashes.items():
1038
+ path = _checkout_file(root, relative)
1039
+ if _sha256_file(path) != expected:
1040
+ raise DriverError("SOURCE_HASH_MISMATCH", f"source hash mismatch for {relative}")
1041
+ if _sha256_file(_checkout_file(root, policy.license_evidence_path)) != (
1042
+ policy.license_evidence_sha256
1043
+ ):
1044
+ raise DriverError("LICENSE_STATE_MISMATCH", "license evidence hash mismatch")
1045
+
1046
+ git_marker = root / ".git"
1047
+ if not git_marker.exists():
1048
+ return root, "source_hash_set"
1049
+ head = read_checkout_head(root)
1050
+ if head != policy.commit:
1051
+ raise DriverError("UPSTREAM_REVISION_MISMATCH", "InfoCQR checkout revision mismatch")
1052
+ if policy.require_clean_checkout:
1053
+ _require_clean_checkout(root)
1054
+ return root, "git_commit_and_source_hash_set"
1055
+
1056
+
1057
+ def audit_source_symbols(root: Path, policy: CompatibilityPolicy) -> dict[str, tuple[str, ...]]:
1058
+ del policy
1059
+ expected_functions = {
1060
+ "rewrite_chatgpt_zsl.py": ("generate_rewrite",),
1061
+ "rewrite_chatgpt_inctx.py": ("generate_rewrite",),
1062
+ "rewrite_chatgpt_editor.py": ("generate_rewrite",),
1063
+ "rewrite_chatgpt_self_editor.py": ("generate_rewrite",),
1064
+ POSTPROCESS_PATH: ("main",),
1065
+ FUSE_PATH: ("main",),
1066
+ T5_TEST_PATH: ("main",),
1067
+ T5_TRAIN_PATH: ("main",),
1068
+ }
1069
+ result: dict[str, tuple[str, ...]] = {}
1070
+ for relative, names in expected_functions.items():
1071
+ tree = ast.parse(_checkout_file(root, relative).read_text(encoding="utf-8"))
1072
+ found = {node.name for node in tree.body if isinstance(node, ast.FunctionDef)}
1073
+ if not set(names) <= found:
1074
+ raise DriverError("UPSTREAM_API_MISMATCH", f"missing official symbol in {relative}")
1075
+ result[relative] = names
1076
+ return result
1077
+
1078
+
1079
+ def _load_official_generators(root: Path, policy: CompatibilityPolicy) -> dict[str, ModuleType]:
1080
+ loaded: dict[str, ModuleType] = {}
1081
+ sentinel = object()
1082
+ original = {name: sys.modules.get(name, sentinel) for name in ("openai", "jsonlines", "tqdm")}
1083
+ openai_stub = ModuleType("openai")
1084
+ openai_stub.ChatCompletion = SimpleNamespace(
1085
+ create=lambda **_kwargs: (_ for _ in ()).throw(
1086
+ DriverError("UPSTREAM_API_MISMATCH", "teacher called before backend binding")
1087
+ )
1088
+ )
1089
+ jsonlines_stub = ModuleType("jsonlines")
1090
+ jsonlines_stub.open = lambda *_args, **_kwargs: (_ for _ in ()).throw(
1091
+ DriverError("UPSTREAM_API_MISMATCH", "JSONL main path is not enabled")
1092
+ )
1093
+ tqdm_stub = ModuleType("tqdm")
1094
+ tqdm_stub.tqdm = lambda value, *_args, **_kwargs: value
1095
+ sys.modules.update({"openai": openai_stub, "jsonlines": jsonlines_stub, "tqdm": tqdm_stub})
1096
+ try:
1097
+ for index, profile in enumerate(sorted(_PROFILES)):
1098
+ source = policy.prompt_profiles[profile]["source_path"]
1099
+ module = _load_module(f"_agentinputlab_infocqr_{profile}_{index}", root / source)
1100
+ function = getattr(module, "generate_rewrite", None)
1101
+ if not callable(function):
1102
+ raise DriverError("UPSTREAM_API_MISMATCH", "generate_rewrite is unavailable")
1103
+ loaded[profile] = module
1104
+ finally:
1105
+ for name, value in original.items():
1106
+ if value is sentinel:
1107
+ sys.modules.pop(name, None)
1108
+ else:
1109
+ sys.modules[name] = value
1110
+ return loaded
1111
+
1112
+
1113
+ def validate_request(
1114
+ value: Mapping[str, Any],
1115
+ policy: CompatibilityPolicy,
1116
+ *,
1117
+ backend_config: BackendConfig | None,
1118
+ mounted_cache: MountedCache | None,
1119
+ ) -> ValidatedRequest:
1120
+ _exact_keys(value, set(_ROOT_FIELDS), "worker request")
1121
+ if value.get("method_id") != METHOD_ID:
1122
+ raise DriverError("PROFILE_IDENTITY_MISMATCH", "request targets another method")
1123
+ release_id = _text(value.get("release_id"), "release_id")
1124
+ if release_id not in _RELEASES:
1125
+ raise DriverError("PROFILE_IDENTITY_MISMATCH", "unsupported InfoCQR release")
1126
+ if value.get("upstream_commit") != policy.commit:
1127
+ raise DriverError("UPSTREAM_REVISION_MISMATCH", "request revision mismatch")
1128
+ if value.get("protocol_version") != PROTOCOL_VERSION:
1129
+ raise DriverError("PROTOCOL_MISMATCH", "request protocol mismatch")
1130
+ request_id = _hash(value.get("request_id"), "request_id")
1131
+ identity = {key: value[key] for key in _ROOT_FIELDS if key != "request_id"}
1132
+ if request_id != _canonical_hash(identity):
1133
+ raise DriverError("REQUEST_ID_MISMATCH", "request_id is invalid")
1134
+
1135
+ payload = _mapping(value.get("payload"), "request payload")
1136
+ _exact_keys(payload, set(_PAYLOAD_FIELDS), "request payload")
1137
+ if payload.get("source_license_acknowledged") is not True:
1138
+ raise DriverError("SOURCE_LICENSE_NOT_ACKNOWLEDGED", "per-request license gate failed")
1139
+ operation = _text(payload.get("operation"), "operation")
1140
+ prompt_profile = _text(payload.get("prompt_profile"), "prompt profile")
1141
+ expected_operation, expected_profile = _RELEASES[release_id]
1142
+ if operation != expected_operation or (
1143
+ expected_profile != "*" and prompt_profile != expected_profile
1144
+ ):
1145
+ raise DriverError("PROFILE_IDENTITY_MISMATCH", "release operation/profile mismatch")
1146
+ if operation == "live_teacher" and prompt_profile not in _PROFILES:
1147
+ raise DriverError("PROFILE_IDENTITY_MISMATCH", "live prompt profile is unsupported")
1148
+ if operation == "t5_student" and prompt_profile != "t5_student":
1149
+ raise DriverError("PROFILE_IDENTITY_MISMATCH", "T5 student profile mismatch")
1150
+
1151
+ prompt_hash = _text(payload.get("prompt_source_sha256"), "prompt source hash")
1152
+ if operation != "t5_student":
1153
+ prompt_hash = _hash(prompt_hash, "prompt source hash")
1154
+ if prompt_hash != policy.prompt_profiles[prompt_profile]["source_sha256"]:
1155
+ raise DriverError("PROMPT_IDENTITY_MISMATCH", "prompt source hash mismatch")
1156
+ elif prompt_hash:
1157
+ if prompt_hash != policy.source_hashes[T5_TEST_PATH]:
1158
+ raise DriverError("PROMPT_IDENTITY_MISMATCH", "T5 source hash mismatch")
1159
+
1160
+ dataset_id = _text(payload.get("dataset_id"), "dataset id")
1161
+ common_support = release_id == "rewrite.infocqr.common_support_rw_zsl"
1162
+ if not common_support and dataset_id.lower() != "qrecc":
1163
+ raise DriverError("DATASET_IDENTITY_MISMATCH", "InfoCQR worker requires QReCC")
1164
+ if common_support and payload.get("profile_kind") != "controlled_adapter":
1165
+ raise DriverError(
1166
+ "PROFILE_IDENTITY_MISMATCH",
1167
+ "InfoCQR common-support release requires controlled_adapter",
1168
+ )
1169
+ dataset_revision = _text(payload.get("dataset_revision"), "dataset revision")
1170
+ split = _text(payload.get("split"), "split")
1171
+ conversation_source = _text(payload.get("conversation_source"), "conversation source")
1172
+ conversation_no = _positive_int(payload.get("conversation_no"), "conversation_no")
1173
+ turn_no = _positive_int(payload.get("turn_no"), "turn_no")
1174
+ query = _bounded_text(payload.get("query"), "query")
1175
+ new_context = _string_sequence(payload.get("new_context"), "new_context")
1176
+ if len(new_context) % 2 != 0:
1177
+ raise DriverError(
1178
+ "CONVERSATION_SCHEMA_INVALID", "QReCC NewContext must alternate complete Q/A pairs"
1179
+ )
1180
+ if turn_no == 1 and new_context:
1181
+ raise DriverError("CONVERSATION_SCHEMA_INVALID", "first turn cannot have NewContext")
1182
+
1183
+ dependencies = _mapping(value.get("dependency_fingerprints"), "dependency fingerprints")
1184
+ _exact_keys(dependencies, {"backend", "retriever"}, "dependency fingerprints")
1185
+ backend_fp = dict(_mapping(dependencies.get("backend"), "backend fingerprint"))
1186
+ retriever_fp = dict(_mapping(dependencies.get("retriever"), "retriever fingerprint"))
1187
+ if not retriever_fp:
1188
+ raise DriverError(
1189
+ "RETRIEVER_IDENTITY_MISSING", "retrieval corpus/retriever fingerprint is required"
1190
+ )
1191
+ retrieval_corpus_id = _text(payload.get("retrieval_corpus_id"), "retrieval corpus id")
1192
+ if operation == "live_teacher":
1193
+ if backend_config is None or _canonical_json(backend_fp) != _canonical_json(
1194
+ backend_config.fingerprint
1195
+ ):
1196
+ raise DriverError("BACKEND_IDENTITY_MISMATCH", "request model differs from startup")
1197
+ elif backend_fp:
1198
+ raise DriverError("BACKEND_IDENTITY_MISMATCH", "non-live request cannot bind a backend")
1199
+
1200
+ cache_id = _optional_text(payload.get("cache_artifact_id"), "cache artifact id")
1201
+ cache_hash = _optional_hash(payload.get("cache_artifact_sha256"), "cache artifact hash")
1202
+ if operation == "cached_replay":
1203
+ if mounted_cache is None:
1204
+ raise DriverError("CACHE_ARTIFACT_UNAVAILABLE", "cache is not mounted")
1205
+ if (
1206
+ cache_id != mounted_cache.artifact_id
1207
+ or cache_hash != mounted_cache.sha256
1208
+ or prompt_profile != mounted_cache.profile
1209
+ or split != mounted_cache.split
1210
+ ):
1211
+ raise DriverError("CACHE_IDENTITY_MISMATCH", "mounted cache identity mismatch")
1212
+ elif cache_id or cache_hash:
1213
+ raise DriverError("CACHE_IDENTITY_MISMATCH", "live request cannot inject a cache")
1214
+
1215
+ allow_truth = payload.get("allow_first_turn_truth_rewrite")
1216
+ if not isinstance(allow_truth, bool):
1217
+ raise DriverError("INVALID_SCHEMA", "allow_first_turn_truth_rewrite must be boolean")
1218
+ profile_kind = _text(payload.get("profile_kind"), "profile kind")
1219
+ if profile_kind not in {"official_native", "controlled_adapter", "artifact_replay"}:
1220
+ raise DriverError("PROFILE_IDENTITY_MISMATCH", "unsupported profile kind")
1221
+ if operation == "cached_replay" and profile_kind != "artifact_replay":
1222
+ raise DriverError("PROFILE_IDENTITY_MISMATCH", "cache must be artifact_replay")
1223
+ if operation == "live_teacher" and profile_kind == "artifact_replay":
1224
+ raise DriverError("PROFILE_IDENTITY_MISMATCH", "live teacher cannot be artifact_replay")
1225
+ if operation == "live_teacher" and profile_kind == "official_native":
1226
+ if (
1227
+ backend_config is None
1228
+ or not backend_config.model.startswith(OFFICIAL_MODEL_NAME)
1229
+ or backend_config.temperature != 0
1230
+ or backend_config.max_output_tokens < OFFICIAL_MAX_TOKENS
1231
+ ):
1232
+ raise DriverError(
1233
+ "PROFILE_IDENTITY_MISMATCH",
1234
+ "official_native requires the official teacher family and generation controls",
1235
+ )
1236
+ if prompt_profile == "t5_edit":
1237
+ raise DriverError(
1238
+ "PROFILE_IDENTITY_MISMATCH",
1239
+ "user-supplied T5 candidates are controlled_adapter inputs",
1240
+ )
1241
+
1242
+ initial_rewrite = _optional_bounded_text(payload.get("initial_rewrite"), "initial rewrite")
1243
+ initial_hash = _optional_hash(
1244
+ payload.get("initial_rewrite_source_sha256"), "initial rewrite source hash"
1245
+ )
1246
+ if operation == "live_teacher" and prompt_profile == "t5_edit":
1247
+ if not initial_rewrite or not initial_hash:
1248
+ raise DriverError(
1249
+ "INITIAL_REWRITE_IDENTITY_MISSING",
1250
+ "official T5 editor requires a candidate and artifact hash",
1251
+ )
1252
+ elif initial_rewrite or initial_hash:
1253
+ raise DriverError(
1254
+ "INITIAL_REWRITE_IDENTITY_MISMATCH", "profile cannot inject an initial rewrite"
1255
+ )
1256
+
1257
+ controls = _validate_controls(payload.get("controls"))
1258
+ reservation = _mapping(value.get("minimum_reservation"), "minimum_reservation")
1259
+ expected_calls = (
1260
+ 2
1261
+ if operation == "live_teacher" and prompt_profile == "self_edit"
1262
+ else (1 if operation == "live_teacher" else 0)
1263
+ )
1264
+ _exact_keys(reservation, {"model_calls"}, "minimum_reservation")
1265
+ if _nonnegative_int(reservation.get("model_calls"), "reserved model calls") != expected_calls:
1266
+ raise DriverError("RESERVATION_MISMATCH", "model-call reservation mismatch")
1267
+ if controls.max_model_calls < expected_calls:
1268
+ raise DriverError("MODEL_CALL_BUDGET_EXCEEDED", "reservation exceeds model-call budget")
1269
+
1270
+ return ValidatedRequest(
1271
+ request_id=request_id,
1272
+ release_id=release_id,
1273
+ operation=operation,
1274
+ task_id=_text(payload.get("task_id"), "task id"),
1275
+ dataset_id=dataset_id,
1276
+ dataset_revision=dataset_revision,
1277
+ split=split,
1278
+ conversation_source=conversation_source,
1279
+ conversation_no=conversation_no,
1280
+ turn_no=turn_no,
1281
+ query=query,
1282
+ new_context=new_context,
1283
+ prompt_profile=prompt_profile,
1284
+ prompt_source_sha256=prompt_hash,
1285
+ cache_artifact_id=cache_id,
1286
+ cache_artifact_sha256=cache_hash,
1287
+ allow_first_turn_truth_rewrite=allow_truth,
1288
+ retrieval_corpus_id=retrieval_corpus_id,
1289
+ profile_kind=profile_kind,
1290
+ initial_rewrite=initial_rewrite,
1291
+ initial_rewrite_source_sha256=initial_hash,
1292
+ controls=controls,
1293
+ seed=_nonnegative_int(payload.get("seed"), "seed"),
1294
+ backend_fingerprint=backend_fp,
1295
+ retriever_fingerprint=retriever_fp,
1296
+ )
1297
+
1298
+
1299
+ def _validate_author_cache_record(
1300
+ value: Mapping[str, Any], profile: str, line_no: int
1301
+ ) -> Mapping[str, Any]:
1302
+ try:
1303
+ source = _text(value["Conversation_source"], "cache Conversation_source")
1304
+ conversation_no = _positive_int(value["Conversation_no"], "cache Conversation_no")
1305
+ turn_no = _positive_int(value["Turn_no"], "cache Turn_no")
1306
+ query = _bounded_text(value["Question"], "cache Question")
1307
+ new_context = _string_sequence(value["NewContext"], "cache NewContext")
1308
+ except KeyError as exc:
1309
+ raise DriverError(
1310
+ "CACHE_SCHEMA_INVALID", f"cache line {line_no} lacks a QReCC identity field"
1311
+ ) from exc
1312
+ if len(new_context) % 2 != 0:
1313
+ raise DriverError("CACHE_SCHEMA_INVALID", "cache NewContext must contain Q/A pairs")
1314
+ candidate_key = "GPT_rewrite" if profile in {"rw_zsl", "rw_fsl"} else "Editor_rewrite"
1315
+ if candidate_key not in value:
1316
+ raise DriverError("CACHE_SCHEMA_INVALID", f"cache line lacks {candidate_key}")
1317
+ initial_key = "T5_rewrite" if profile == "t5_edit" else "GPT_rewrite"
1318
+ initial: Any = ""
1319
+ if profile in {"t5_edit", "self_edit"}:
1320
+ if initial_key not in value:
1321
+ raise DriverError("CACHE_SCHEMA_INVALID", f"cache line lacks {initial_key}")
1322
+ initial = value[initial_key]
1323
+ _legacy_candidate(initial)
1324
+ _legacy_candidate(value[candidate_key])
1325
+ return {
1326
+ "conversation_source": source,
1327
+ "conversation_no": conversation_no,
1328
+ "turn_no": turn_no,
1329
+ "query": query,
1330
+ "new_context": new_context,
1331
+ "candidate": value[candidate_key],
1332
+ "initial_rewrite": initial,
1333
+ }
1334
+
1335
+
1336
+ def _legacy_candidate(value: Any) -> tuple[str, Mapping[str, Any]]:
1337
+ if isinstance(value, str):
1338
+ if not value.strip():
1339
+ raise DriverError("CACHE_SCHEMA_INVALID", "legacy candidate is empty")
1340
+ return value, {}
1341
+ root = _mapping(value, "legacy ChatCompletion response")
1342
+ choices = root.get("choices")
1343
+ if not isinstance(choices, Sequence) or isinstance(choices, (str, bytes)) or len(choices) < 1:
1344
+ raise DriverError("CACHE_SCHEMA_INVALID", "legacy response choices are invalid")
1345
+ message = _mapping(_mapping(choices[0], "legacy choice").get("message"), "legacy message")
1346
+ text = _bounded_text(message.get("content"), "legacy candidate")
1347
+ raw_usage = root.get("usage", {})
1348
+ usage = dict(_mapping(raw_usage, "legacy usage")) if raw_usage is not None else {}
1349
+ for key in ("prompt_tokens", "completion_tokens", "total_tokens"):
1350
+ if key in usage:
1351
+ _nonnegative_int(usage[key], f"legacy {key}")
1352
+ return text, usage
1353
+
1354
+
1355
+ def _official_postprocess_compat(
1356
+ candidate: str,
1357
+ *,
1358
+ question: str,
1359
+ turn_no: int,
1360
+ editor: bool,
1361
+ initial_rewrite: str,
1362
+ ) -> tuple[str, str]:
1363
+ """Exact branch order from pinned ``post_processing.py`` lines 33-51."""
1364
+
1365
+ if turn_no <= 1:
1366
+ return candidate, "first_turn_unchanged"
1367
+ fallback = initial_rewrite if editor else question
1368
+ if editor and not fallback.strip():
1369
+ raise DriverError("UPSTREAM_OUTPUT_INVALID", "editor fallback rewrite is empty")
1370
+ if "N/A" in candidate:
1371
+ return fallback, "n_a_fallback"
1372
+ if not candidate or candidate[-1] != "?":
1373
+ return fallback, "non_question_fallback"
1374
+ lowered = candidate.lower()
1375
+ if "no edit" in lowered or "no need to edit" in lowered:
1376
+ return fallback, "no_edit_fallback"
1377
+ return candidate, "unchanged"
1378
+
1379
+
1380
+ def read_checkout_head(root: Path) -> str:
1381
+ marker = root / ".git"
1382
+ git_dir = marker
1383
+ if marker.is_file():
1384
+ raw = marker.read_text(encoding="utf-8").strip()
1385
+ if not raw.startswith("gitdir: "):
1386
+ raise DriverError("UPSTREAM_REVISION_MISMATCH", "invalid .git pointer")
1387
+ target = Path(raw[8:])
1388
+ git_dir = (root / target).resolve() if not target.is_absolute() else target.resolve()
1389
+ if not git_dir.is_dir():
1390
+ raise DriverError("UPSTREAM_REVISION_MISMATCH", "checkout Git metadata missing")
1391
+ head = (git_dir / "HEAD").read_text(encoding="utf-8").strip()
1392
+ if _COMMIT_RE.fullmatch(head):
1393
+ return head.lower()
1394
+ if not head.startswith("ref: "):
1395
+ raise DriverError("UPSTREAM_REVISION_MISMATCH", "checkout HEAD is invalid")
1396
+ ref = _safe_git_ref(head[5:])
1397
+ ref_file = git_dir / ref
1398
+ if ref_file.is_file():
1399
+ commit = ref_file.read_text(encoding="utf-8").strip()
1400
+ if _COMMIT_RE.fullmatch(commit):
1401
+ return commit.lower()
1402
+ packed = git_dir / "packed-refs"
1403
+ if packed.is_file():
1404
+ for line in packed.read_text(encoding="utf-8").splitlines():
1405
+ if line.startswith("#") or line.startswith("^"):
1406
+ continue
1407
+ parts = line.split(" ", 1)
1408
+ if len(parts) == 2 and parts[1] == ref and _COMMIT_RE.fullmatch(parts[0]):
1409
+ return parts[0].lower()
1410
+ raise DriverError("UPSTREAM_REVISION_MISMATCH", "checkout ref cannot be resolved")
1411
+
1412
+
1413
+ def _require_clean_checkout(root: Path) -> None:
1414
+ try:
1415
+ completed = subprocess.run(
1416
+ ["git", "-C", str(root), "status", "--porcelain", "--untracked-files=all"],
1417
+ check=False,
1418
+ capture_output=True,
1419
+ text=True,
1420
+ timeout=15,
1421
+ )
1422
+ except (OSError, subprocess.SubprocessError) as exc:
1423
+ raise DriverError("CHECKOUT_DIRTY", "cannot verify clean checkout") from exc
1424
+ if completed.returncode != 0 or completed.stdout.strip():
1425
+ raise DriverError("CHECKOUT_DIRTY", "InfoCQR checkout must be clean")
1426
+
1427
+
1428
+ def _safe_git_ref(value: str) -> str:
1429
+ path = PurePosixPath(value)
1430
+ if path.is_absolute() or ".." in path.parts or not value.startswith("refs/"):
1431
+ raise DriverError("UPSTREAM_REVISION_MISMATCH", "unsafe Git ref")
1432
+ return value
1433
+
1434
+
1435
+ def serve(runtime: InfoCQRRuntime, input_stream: TextIO, output_stream: TextIO) -> None:
1436
+ for raw_line in input_stream:
1437
+ request_id = ""
1438
+ try:
1439
+ if len(raw_line.encode("utf-8")) > MAX_REQUEST_BYTES:
1440
+ raise DriverError("REQUEST_TOO_LARGE", "request exceeds byte limit")
1441
+ value = _mapping(_loads_strict_json(raw_line), "JSONL request")
1442
+ if isinstance(value.get("request_id"), str):
1443
+ request_id = value["request_id"][:128]
1444
+ response = runtime.run(value)
1445
+ except DriverError as exc:
1446
+ response = _failure_response(request_id, exc)
1447
+ except Exception as exc: # pragma: no cover - defensive redaction boundary
1448
+ response = _failure_response(
1449
+ request_id,
1450
+ DriverError("INTERNAL_WORKER_ERROR", f"worker failed with {type(exc).__name__}"),
1451
+ )
1452
+ output_stream.write(_canonical_json(response) + "\n")
1453
+ output_stream.flush()
1454
+
1455
+
1456
+ def _failure_response(request_id: str, error: DriverError) -> dict[str, Any]:
1457
+ response: dict[str, Any] = {
1458
+ "status": "error",
1459
+ "request_id": request_id,
1460
+ "failure_code": error.code,
1461
+ "message": str(error),
1462
+ "consumed": error.consumed,
1463
+ }
1464
+ if error.usage is not None:
1465
+ response["usage"] = dict(error.usage)
1466
+ return response
1467
+
1468
+
1469
+ def _load_module(name: str, path: Path) -> ModuleType:
1470
+ spec = importlib.util.spec_from_file_location(name, path)
1471
+ if spec is None or spec.loader is None:
1472
+ raise DriverError("UPSTREAM_IMPORT_FAILED", "cannot construct source module")
1473
+ module = importlib.util.module_from_spec(spec)
1474
+ try:
1475
+ spec.loader.exec_module(module)
1476
+ except Exception as exc:
1477
+ raise DriverError("UPSTREAM_IMPORT_FAILED", "cannot import official source") from exc
1478
+ return module
1479
+
1480
+
1481
+ def _checkout_file(root: Path, relative: str) -> Path:
1482
+ path = _safe_child(root, relative)
1483
+ if not path.is_file() or path.is_symlink():
1484
+ raise DriverError("SOURCE_UNAVAILABLE", f"required source unavailable: {relative}")
1485
+ return path
1486
+
1487
+
1488
+ def _safe_child(root: Path, relative: str) -> Path:
1489
+ candidate = (root / _safe_relative_path(relative, "relative path")).resolve()
1490
+ try:
1491
+ candidate.relative_to(root)
1492
+ except ValueError as exc:
1493
+ raise DriverError("INVALID_PATH", "path escapes checkout") from exc
1494
+ return candidate
1495
+
1496
+
1497
+ def _safe_relative_path(value: Any, label: str) -> str:
1498
+ text = _text(value, label)
1499
+ path = PurePosixPath(text)
1500
+ if path.is_absolute() or ".." in path.parts or not path.parts:
1501
+ raise DriverError("INVALID_PATH", f"{label} is unsafe")
1502
+ return str(path)
1503
+
1504
+
1505
+ def _sha256_file(path: Path) -> str:
1506
+ digest = hashlib.sha256()
1507
+ try:
1508
+ with path.open("rb") as handle:
1509
+ for chunk in iter(lambda: handle.read(1024 * 1024), b""):
1510
+ digest.update(chunk)
1511
+ except OSError as exc:
1512
+ raise DriverError("SOURCE_UNAVAILABLE", "cannot read required file") from exc
1513
+ return digest.hexdigest()
1514
+
1515
+
1516
+ def _sha256_bytes(value: bytes) -> str:
1517
+ return hashlib.sha256(value).hexdigest()
1518
+
1519
+
1520
+ def _canonical_hash(value: Any) -> str:
1521
+ return _sha256_bytes(_canonical_json(value).encode("utf-8"))
1522
+
1523
+
1524
+ def _canonical_json(value: Any) -> str:
1525
+ return json.dumps(
1526
+ value,
1527
+ ensure_ascii=False,
1528
+ sort_keys=True,
1529
+ separators=(",", ":"),
1530
+ allow_nan=False,
1531
+ )
1532
+
1533
+
1534
+ def _loads_strict_json(raw: str) -> Any:
1535
+ def reject_constant(value: str) -> None:
1536
+ raise DriverError("INVALID_JSON", f"non-finite JSON value {value} is forbidden")
1537
+
1538
+ def reject_duplicates(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
1539
+ result: dict[str, Any] = {}
1540
+ for key, value in pairs:
1541
+ if key in result:
1542
+ raise DriverError("INVALID_JSON", f"duplicate JSON key: {key}")
1543
+ result[key] = value
1544
+ return result
1545
+
1546
+ try:
1547
+ return json.loads(raw, parse_constant=reject_constant, object_pairs_hook=reject_duplicates)
1548
+ except json.JSONDecodeError as exc:
1549
+ raise DriverError("INVALID_JSON", "invalid JSON input") from exc
1550
+
1551
+
1552
+ def _mapping(value: Any, label: str) -> Mapping[str, Any]:
1553
+ if not isinstance(value, Mapping) or any(not isinstance(key, str) for key in value):
1554
+ raise DriverError("INVALID_SCHEMA", f"{label} must be a string-keyed object")
1555
+ return value
1556
+
1557
+
1558
+ def _exact_keys(value: Mapping[str, Any], expected: set[str], label: str) -> None:
1559
+ if set(value) != expected:
1560
+ raise DriverError("INVALID_SCHEMA", f"{label} fields do not match the protocol")
1561
+
1562
+
1563
+ def _text(value: Any, label: str) -> str:
1564
+ if not isinstance(value, str) or not value.strip():
1565
+ raise DriverError("INVALID_SCHEMA", f"{label} must be non-empty text")
1566
+ return value
1567
+
1568
+
1569
+ def _optional_text(value: Any, label: str) -> str:
1570
+ if not isinstance(value, str):
1571
+ raise DriverError("INVALID_SCHEMA", f"{label} must be text")
1572
+ return value
1573
+
1574
+
1575
+ def _bounded_text(value: Any, label: str) -> str:
1576
+ text = _text(value, label)
1577
+ if len(text) > MAX_TEXT_CHARS:
1578
+ raise DriverError("INVALID_SCHEMA", f"{label} exceeds text limit")
1579
+ return text
1580
+
1581
+
1582
+ def _optional_bounded_text(value: Any, label: str) -> str:
1583
+ text = _optional_text(value, label)
1584
+ if len(text) > MAX_TEXT_CHARS:
1585
+ raise DriverError("INVALID_SCHEMA", f"{label} exceeds text limit")
1586
+ return text
1587
+
1588
+
1589
+ def _hash(value: Any, label: str) -> str:
1590
+ text = _text(value, label).lower()
1591
+ if _HASH_RE.fullmatch(text) is None:
1592
+ raise DriverError("INVALID_SCHEMA", f"{label} must be a SHA-256 digest")
1593
+ return text
1594
+
1595
+
1596
+ def _optional_hash(value: Any, label: str) -> str:
1597
+ text = _optional_text(value, label)
1598
+ return "" if not text else _hash(text, label)
1599
+
1600
+
1601
+ def _positive_int(value: Any, label: str) -> int:
1602
+ if isinstance(value, bool) or not isinstance(value, int) or value < 1:
1603
+ raise DriverError("INVALID_SCHEMA", f"{label} must be a positive integer")
1604
+ return value
1605
+
1606
+
1607
+ def _nonnegative_int(value: Any, label: str) -> int:
1608
+ if isinstance(value, bool) or not isinstance(value, int) or value < 0:
1609
+ raise DriverError("INVALID_SCHEMA", f"{label} must be a non-negative integer")
1610
+ return value
1611
+
1612
+
1613
+ def _finite_float(value: Any, label: str) -> float:
1614
+ if isinstance(value, bool) or not isinstance(value, (int, float)):
1615
+ raise DriverError("INVALID_SCHEMA", f"{label} must be numeric")
1616
+ result = float(value)
1617
+ if not math.isfinite(result):
1618
+ raise DriverError("INVALID_SCHEMA", f"{label} must be finite")
1619
+ return result
1620
+
1621
+
1622
+ def _nonnegative_float(value: Any, label: str) -> float:
1623
+ result = _finite_float(value, label)
1624
+ if result < 0:
1625
+ raise DriverError("INVALID_SCHEMA", f"{label} must be non-negative")
1626
+ return result
1627
+
1628
+
1629
+ def _positive_float(value: Any, label: str) -> float:
1630
+ result = _finite_float(value, label)
1631
+ if result <= 0:
1632
+ raise DriverError("INVALID_SCHEMA", f"{label} must be positive")
1633
+ return result
1634
+
1635
+
1636
+ def _string_sequence(value: Any, label: str) -> tuple[str, ...]:
1637
+ if isinstance(value, (str, bytes)) or not isinstance(value, Sequence):
1638
+ raise DriverError("INVALID_SCHEMA", f"{label} must be a string sequence")
1639
+ if len(value) > 100_000:
1640
+ raise DriverError("INVALID_SCHEMA", f"{label} exceeds sequence limit")
1641
+ return tuple(_optional_bounded_text(item, f"{label} item") for item in value)
1642
+
1643
+
1644
+ def _messages(value: Any) -> tuple[Mapping[str, str], ...]:
1645
+ if isinstance(value, (str, bytes)) or not isinstance(value, Sequence) or len(value) != 1:
1646
+ raise DriverError("UPSTREAM_API_MISMATCH", "official messages must contain one item")
1647
+ item = _mapping(value[0], "official message")
1648
+ _exact_keys(item, {"role", "content"}, "official message")
1649
+ if item.get("role") != "user":
1650
+ raise DriverError("UPSTREAM_API_MISMATCH", "official message role changed")
1651
+ return ({"role": "user", "content": _bounded_text(item.get("content"), "prompt")},)
1652
+
1653
+
1654
+ def _validate_controls(value: Any) -> Controls:
1655
+ item = _mapping(value, "controls")
1656
+ _exact_keys(item, set(_CONTROL_FIELDS), "controls")
1657
+ return Controls(
1658
+ max_model_calls=_nonnegative_int(item.get("max_model_calls"), "max_model_calls"),
1659
+ max_tokens=_nonnegative_int(item.get("max_tokens"), "max_tokens"),
1660
+ max_cost_usd=_nonnegative_float(item.get("max_cost_usd"), "max_cost_usd"),
1661
+ )
1662
+
1663
+
1664
+ def _validate_base_url(value: str) -> str:
1665
+ parsed = urllib.parse.urlparse(value)
1666
+ if (
1667
+ parsed.scheme not in {"http", "https"}
1668
+ or not parsed.netloc
1669
+ or parsed.query
1670
+ or parsed.fragment
1671
+ ):
1672
+ raise DriverError("INVALID_BACKEND_CONFIG", "backend base_url is invalid")
1673
+ if parsed.username or parsed.password:
1674
+ raise DriverError("INVALID_BACKEND_CONFIG", "backend URL cannot contain credentials")
1675
+ return value.rstrip("/")
1676
+
1677
+
1678
+ def _mounted_cache_from_args(
1679
+ args: argparse.Namespace, checkout: Path, policy: CompatibilityPolicy
1680
+ ) -> MountedCache | None:
1681
+ if args.known_cache:
1682
+ if any((args.cache_path, args.cache_sha256, args.cache_profile, args.cache_split)):
1683
+ raise DriverError(
1684
+ "INVALID_CACHE_CONFIG", "known cache cannot be combined with custom cache fields"
1685
+ )
1686
+ try:
1687
+ item = policy.known_caches[args.known_cache]
1688
+ except KeyError as exc:
1689
+ raise DriverError("INVALID_CACHE_CONFIG", "unknown manifest cache id") from exc
1690
+ return MountedCache.load(
1691
+ _safe_child(checkout, item["path"]),
1692
+ artifact_id=args.known_cache,
1693
+ expected_sha256=item["sha256"],
1694
+ profile=item["profile"],
1695
+ split=item["split"],
1696
+ )
1697
+ custom = (args.cache_path, args.cache_sha256, args.cache_profile, args.cache_split)
1698
+ if not any(custom):
1699
+ return None
1700
+ if not all(custom) or not args.cache_artifact_id:
1701
+ raise DriverError(
1702
+ "INVALID_CACHE_CONFIG", "custom cache requires path, id, SHA, profile, and split"
1703
+ )
1704
+ return MountedCache.load(
1705
+ Path(args.cache_path),
1706
+ artifact_id=args.cache_artifact_id,
1707
+ expected_sha256=args.cache_sha256,
1708
+ profile=args.cache_profile,
1709
+ split=args.cache_split,
1710
+ )
1711
+
1712
+
1713
+ def main(argv: Sequence[str] | None = None) -> int:
1714
+ parser = argparse.ArgumentParser(description=__doc__)
1715
+ parser.add_argument("--checkout", required=True)
1716
+ parser.add_argument("--manifest", default=str(DEFAULT_MANIFEST))
1717
+ parser.add_argument("--backend-config-json")
1718
+ parser.add_argument("--known-cache")
1719
+ parser.add_argument("--cache-path")
1720
+ parser.add_argument("--cache-artifact-id")
1721
+ parser.add_argument("--cache-sha256")
1722
+ parser.add_argument("--cache-profile", choices=sorted(_PROFILES))
1723
+ parser.add_argument("--cache-split")
1724
+ parser.add_argument("--acknowledge-noassertion-license", action="store_true")
1725
+ parser.add_argument("--verify-only", action="store_true")
1726
+ args = parser.parse_args(argv)
1727
+ try:
1728
+ policy = load_compatibility_policy(Path(args.manifest))
1729
+ checkout, identity_mode = verify_checkout(Path(args.checkout), policy)
1730
+ audit_source_symbols(checkout, policy)
1731
+ cache = _mounted_cache_from_args(args, checkout, policy)
1732
+ if args.verify_only:
1733
+ print(
1734
+ _canonical_json(
1735
+ {
1736
+ "status": "ok",
1737
+ "upstream_commit": UPSTREAM_COMMIT,
1738
+ "license_spdx": "NOASSERTION",
1739
+ "checkout_identity_mode": identity_mode,
1740
+ "cache_artifact_sha256": cache.sha256 if cache else "",
1741
+ "t5_student_checkpoint_available": False,
1742
+ }
1743
+ )
1744
+ )
1745
+ return 0
1746
+ backend_config = (
1747
+ BackendConfig.from_json(args.backend_config_json) if args.backend_config_json else None
1748
+ )
1749
+ backend = OpenAICompatibleBackend(backend_config) if backend_config else None
1750
+ runtime = InfoCQRRuntime(
1751
+ checkout,
1752
+ backend_config,
1753
+ backend,
1754
+ cache=cache,
1755
+ source_license_acknowledged=args.acknowledge_noassertion_license,
1756
+ policy=policy,
1757
+ )
1758
+ serve(runtime, sys.stdin, sys.stdout)
1759
+ return 0
1760
+ except DriverError as exc:
1761
+ print(_canonical_json(_failure_response("", exc)))
1762
+ return 2
1763
+
1764
+
1765
+ if __name__ == "__main__":
1766
+ raise SystemExit(main())