2sagaco48 1.0.0

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 (365) hide show
  1. package/diagnostics.mjs +141 -0
  2. package/dist/compute.worker-j5ahIpF-.js +1 -0
  3. package/dist/graph.worker-DG6iGCB9.js +1 -0
  4. package/dist/index.html +2314 -0
  5. package/flatten-guide.md +248 -0
  6. package/index.html +12 -0
  7. package/package.json +38 -0
  8. package/src/App.orig.tsx +204 -0
  9. package/src/App.orig1.tsx +27 -0
  10. package/src/App.orig2.tsx +25 -0
  11. package/src/App.tsx +3 -0
  12. package/src/BaseApp.tsx +18 -0
  13. package/src/INTEGRATION_LEDGER.md +22 -0
  14. package/src/PERSIST_CANARY.orig.txt +1 -0
  15. package/src/PERSIST_CANARY.txt +1 -0
  16. package/src/REGRESSION_LEDGER.md +651 -0
  17. package/src/TEMPLATE_PIPELINE_AUDIT.md +208 -0
  18. package/src/WILLIAMS_PERSONA_GUIDE.md +62 -0
  19. package/src/chat/VeritasChat.tsx +69 -0
  20. package/src/chat/synthesis.ts +31 -0
  21. package/src/chat/tier.ts +45 -0
  22. package/src/components/AdaptersPage.orig.tsx +99 -0
  23. package/src/components/AdaptersPage.tsx +3 -0
  24. package/src/components/AdversarialPanel.tsx +136 -0
  25. package/src/components/AnchorBaselinePanel.tsx +75 -0
  26. package/src/components/AnswerPanel.tsx +60 -0
  27. package/src/components/ArtifactPanel.tsx +43 -0
  28. package/src/components/ChatApp.orig.tsx +1582 -0
  29. package/src/components/ChatApp.orig1.tsx +722 -0
  30. package/src/components/ChatApp.tsx +95 -0
  31. package/src/components/ChatAugmentPanels.tsx +73 -0
  32. package/src/components/CitationLedgerPanel.tsx +313 -0
  33. package/src/components/ComputeSandboxPanel.tsx +130 -0
  34. package/src/components/ConfigPanel.tsx +110 -0
  35. package/src/components/ControlPlanePage.tsx +195 -0
  36. package/src/components/CreativeTreeLifePage.tsx +234 -0
  37. package/src/components/CreativeTreeOfLifePanel.tsx +149 -0
  38. package/src/components/DebugTracePanel.tsx +137 -0
  39. package/src/components/DeepReasoningTrace.tsx +48 -0
  40. package/src/components/EntitySheetPanel.tsx +51 -0
  41. package/src/components/FailureModesPanel.tsx +104 -0
  42. package/src/components/GBSDashboard.tsx +239 -0
  43. package/src/components/GraphView.tsx +116 -0
  44. package/src/components/HUD.tsx +125 -0
  45. package/src/components/HypothesisPanel.tsx +67 -0
  46. package/src/components/InnovationGenomeEngine.tsx +792 -0
  47. package/src/components/InnovationPersonaGuide.tsx +348 -0
  48. package/src/components/InnovationPersonaPanel.tsx +289 -0
  49. package/src/components/LiveResourceHUD.tsx +109 -0
  50. package/src/components/LongWriterPanel.tsx +112 -0
  51. package/src/components/MainPipelineV10Bridge.tsx +72 -0
  52. package/src/components/MarkdownLite.tsx +63 -0
  53. package/src/components/MemoryInspector.tsx +38 -0
  54. package/src/components/MemoryMonitor.tsx +52 -0
  55. package/src/components/MemoryStressPanel.tsx +176 -0
  56. package/src/components/ModulesPage.tsx +171 -0
  57. package/src/components/PipelineDebugConsole.orig.tsx +1856 -0
  58. package/src/components/PipelineDebugConsole.tsx +3 -0
  59. package/src/components/PreFlightHUD.tsx +67 -0
  60. package/src/components/PrismaFetchTracePanel.tsx +87 -0
  61. package/src/components/ReportOSPanel.tsx +165 -0
  62. package/src/components/ResourceEstimatorPage.tsx +327 -0
  63. package/src/components/RichText.tsx +181 -0
  64. package/src/components/SagaOsPanel.tsx +605 -0
  65. package/src/components/SagaOsReference.tsx +421 -0
  66. package/src/components/SagaOsV2Panel.tsx +594 -0
  67. package/src/components/SagaStyleTab.tsx +382 -0
  68. package/src/components/SageBlueprintPanel.tsx +416 -0
  69. package/src/components/SharedChatInput.tsx +77 -0
  70. package/src/components/StatFinancePanel.tsx +190 -0
  71. package/src/components/StylePersonaPanel.tsx +128 -0
  72. package/src/components/TemplatesPage.tsx +300 -0
  73. package/src/components/TestPanel.tsx +63 -0
  74. package/src/components/TraceLog.tsx +89 -0
  75. package/src/components/V15CalibrationAugment.tsx +1134 -0
  76. package/src/components/V15CalibrationDialog.tsx +1871 -0
  77. package/src/components/V15Overlay.orig.tsx +120 -0
  78. package/src/components/V15Overlay.tsx +4 -0
  79. package/src/components/V15OverlayWrapper.tsx +362 -0
  80. package/src/components/V15Toggle.tsx +34 -0
  81. package/src/console/DiagnosticRecoveryPanel.tsx +358 -0
  82. package/src/console/EngineeringConsole.tsx +103 -0
  83. package/src/console/FictionSystemPanels.tsx +882 -0
  84. package/src/console/InspectorPanels.tsx +254 -0
  85. package/src/console/ManuscriptGraderPanel.tsx +182 -0
  86. package/src/console/RecursiveReviserPanel.tsx +245 -0
  87. package/src/console/SeedControlPanel.tsx +135 -0
  88. package/src/console/StoryControllerPanel.tsx +443 -0
  89. package/src/console/engineBridge.ts +258 -0
  90. package/src/console/gemini.ts +106 -0
  91. package/src/console/grading.ts +250 -0
  92. package/src/console/util.ts +45 -0
  93. package/src/fiction/continuity.ts +372 -0
  94. package/src/fiction/crash-protection.ts +111 -0
  95. package/src/fiction/diagnostics.ts +208 -0
  96. package/src/fiction/diff.ts +74 -0
  97. package/src/fiction/entity-state-machine.ts +214 -0
  98. package/src/fiction/nive-engine.ts +404 -0
  99. package/src/fiction/pipeline-selftest.ts +132 -0
  100. package/src/fiction/seed-control.ts +193 -0
  101. package/src/fiction/story-engine.ts +326 -0
  102. package/src/fiction/types.ts +68 -0
  103. package/src/flatten-guide.md +379 -0
  104. package/src/index.css +14 -0
  105. package/src/index.orig.css +13 -0
  106. package/src/lib/academic-sources.base.ts +188 -0
  107. package/src/lib/academic-sources.orig.ts +28 -0
  108. package/src/lib/academic-sources.ts +10 -0
  109. package/src/lib/advanced-math.ts +119 -0
  110. package/src/lib/adversarial-engine.base.ts +409 -0
  111. package/src/lib/adversarial-engine.ts +82 -0
  112. package/src/lib/ai-revision.ts +623 -0
  113. package/src/lib/app-state.tsx +426 -0
  114. package/src/lib/artifact-registry.ts +97 -0
  115. package/src/lib/artifacts.ts +180 -0
  116. package/src/lib/atlas-dr.ts +167 -0
  117. package/src/lib/browser-mtls.ts +127 -0
  118. package/src/lib/browser-queue.ts +221 -0
  119. package/src/lib/browser-search-scraper.base.ts +382 -0
  120. package/src/lib/browser-search-scraper.orig.ts +90 -0
  121. package/src/lib/browser-search-scraper.ts +10 -0
  122. package/src/lib/calc-interceptor.ts +82 -0
  123. package/src/lib/citation-lane-tap.ts +78 -0
  124. package/src/lib/citation-ledger-store.ts +369 -0
  125. package/src/lib/citation-ledger.ts +203 -0
  126. package/src/lib/compute-sandbox.ts +215 -0
  127. package/src/lib/compute.worker.ts +153 -0
  128. package/src/lib/connectors/gemini.ts +120 -0
  129. package/src/lib/connectors/jina.ts +233 -0
  130. package/src/lib/connectors/marketdata.ts +51 -0
  131. package/src/lib/connectors/prismafetch.base.ts +175 -0
  132. package/src/lib/connectors/prismafetch.ts +1 -0
  133. package/src/lib/connectors/serpapi.ts +65 -0
  134. package/src/lib/connectors/wikidata.ts +44 -0
  135. package/src/lib/constraints.ts +331 -0
  136. package/src/lib/continuation-detector.base.ts +153 -0
  137. package/src/lib/continuation-detector.ts +48 -0
  138. package/src/lib/contradraft.ts +168 -0
  139. package/src/lib/cors-proxy.ts +120 -0
  140. package/src/lib/coverage.ts +81 -0
  141. package/src/lib/debug/architecture-prescription.ts +556 -0
  142. package/src/lib/debug/covea-repair.ts +543 -0
  143. package/src/lib/debug/helios-ground.ts +319 -0
  144. package/src/lib/debug/intent-decomposer.ts +281 -0
  145. package/src/lib/debug/intent-lattice.ts +349 -0
  146. package/src/lib/debug/pipeline-diagnosis.ts +1149 -0
  147. package/src/lib/debug/pipeline-trace-bus.ts +424 -0
  148. package/src/lib/debug/prompt-forge.ts +678 -0
  149. package/src/lib/debug/repair-sites.ts +513 -0
  150. package/src/lib/debug/research-phase.ts +266 -0
  151. package/src/lib/debug/retrieval-context.ts +76 -0
  152. package/src/lib/debug/retrieval-hardener.ts +142 -0
  153. package/src/lib/debug/scraper-debug-runner.ts +576 -0
  154. package/src/lib/debug/scraper-forensics.ts +418 -0
  155. package/src/lib/debug/scraper-lane-roadmap.ts +136 -0
  156. package/src/lib/debug/self-test.ts +415 -0
  157. package/src/lib/debug/step-attribution.ts +211 -0
  158. package/src/lib/debug/template-rubric.ts +301 -0
  159. package/src/lib/debug/unified-innovation.ts +126 -0
  160. package/src/lib/debug/veritas-hybrid-scraper.ts +335 -0
  161. package/src/lib/defense-registry.ts +104 -0
  162. package/src/lib/defenses.ts +162 -0
  163. package/src/lib/deterministic-citation-ledger.ts +174 -0
  164. package/src/lib/elo-registry.base.ts +117 -0
  165. package/src/lib/elo-registry.ts +1 -0
  166. package/src/lib/entity-resolver.ts +291 -0
  167. package/src/lib/failure-modes.ts +267 -0
  168. package/src/lib/feature-registry.ts +69 -0
  169. package/src/lib/flaw-registry.ts +143 -0
  170. package/src/lib/flaws/_template.ts +52 -0
  171. package/src/lib/flaws/builtins.ts +63 -0
  172. package/src/lib/flaws/finance.ts +169 -0
  173. package/src/lib/flaws/fixers.ts +10 -0
  174. package/src/lib/flaws/index.ts +32 -0
  175. package/src/lib/flaws/legal.ts +157 -0
  176. package/src/lib/flaws/medical.ts +188 -0
  177. package/src/lib/flaws/original-defenses-pack.ts +81 -0
  178. package/src/lib/flaws/sample-declarative-pack.json +38 -0
  179. package/src/lib/flaws/selftest.ts +201 -0
  180. package/src/lib/flaws/software-extended.ts +125 -0
  181. package/src/lib/flaws/software-rn-webgl.ts +182 -0
  182. package/src/lib/flaws/statistics-advanced.ts +46 -0
  183. package/src/lib/flaws/statistics.ts +61 -0
  184. package/src/lib/gbse/config.ts +20 -0
  185. package/src/lib/gbse/engine.ts +226 -0
  186. package/src/lib/gbse/graph.ts +118 -0
  187. package/src/lib/gbse/graph.worker.ts +21 -0
  188. package/src/lib/gbse/tests.ts +117 -0
  189. package/src/lib/gbse/tiers.ts +65 -0
  190. package/src/lib/gbse/types.ts +94 -0
  191. package/src/lib/innovation-genome-engine-v2.orig.ts +1001 -0
  192. package/src/lib/innovation-genome-engine-v2.ts +3 -0
  193. package/src/lib/innovation-genome-engine.orig.ts +330 -0
  194. package/src/lib/innovation-genome-engine.ts +3 -0
  195. package/src/lib/innovation-genome-v10.orig.ts +314 -0
  196. package/src/lib/innovation-genome-v10.ts +2 -0
  197. package/src/lib/innovation-genome-v3.orig.ts +2015 -0
  198. package/src/lib/innovation-genome-v3.ts +2 -0
  199. package/src/lib/innovation-genome-v4.orig.ts +1959 -0
  200. package/src/lib/innovation-genome-v4.ts +2 -0
  201. package/src/lib/innovation-genome-v5.orig.ts +1210 -0
  202. package/src/lib/innovation-genome-v5.ts +2 -0
  203. package/src/lib/innovation-genome-v7.orig.ts +2549 -0
  204. package/src/lib/innovation-genome-v7.ts +2 -0
  205. package/src/lib/innovation-genome-v8.orig.ts +1485 -0
  206. package/src/lib/innovation-genome-v8.ts +2 -0
  207. package/src/lib/innovation-genome-v9.orig.ts +643 -0
  208. package/src/lib/innovation-genome-v9.ts +2 -0
  209. package/src/lib/jina.base.ts +293 -0
  210. package/src/lib/jina.ts +1 -0
  211. package/src/lib/live-telemetry.ts +61 -0
  212. package/src/lib/longwriter.ts +84 -0
  213. package/src/lib/manuscript-grade-v2.ts +298 -0
  214. package/src/lib/memory-governor.ts +173 -0
  215. package/src/lib/memory-stress-tests.ts +248 -0
  216. package/src/lib/model-intelligence.ts +48 -0
  217. package/src/lib/model-rotator.ts +75 -0
  218. package/src/lib/models.orig.ts +513 -0
  219. package/src/lib/models.ts +151 -0
  220. package/src/lib/n-deep.base.ts +592 -0
  221. package/src/lib/n-deep.ts +51 -0
  222. package/src/lib/nih-simulator.ts +56 -0
  223. package/src/lib/nih-vulnerability-fixes.ts +460 -0
  224. package/src/lib/omega-templates.base.ts +294 -0
  225. package/src/lib/omega-templates.ts +225 -0
  226. package/src/lib/omni-nexus.ts +64 -0
  227. package/src/lib/oracle-adapters.ts +67 -0
  228. package/src/lib/oracle-registry.ts +163 -0
  229. package/src/lib/orchestrator.ts +357 -0
  230. package/src/lib/output-boundary.ts +235 -0
  231. package/src/lib/overrides/vite-native-chaos-harness.ts +154 -0
  232. package/src/lib/overrides/vite-native-contract-plane.ts +245 -0
  233. package/src/lib/overrides/vite-native-doctor-plane.ts +208 -0
  234. package/src/lib/overrides/vite-native-knowledge-store.ts +267 -0
  235. package/src/lib/overrides/vite-native-policy-plane.ts +190 -0
  236. package/src/lib/overrides/vite-native-replay-plane.ts +197 -0
  237. package/src/lib/overrides/vite-native-runtime-plane.ts +106 -0
  238. package/src/lib/overrides/vite-native-scraper.ts +848 -0
  239. package/src/lib/overrides/vite-native-selftest-functional.ts +217 -0
  240. package/src/lib/overrides/vite-native-selftest.ts +183 -0
  241. package/src/lib/overrides/vite-native-snapshot-plane.ts +123 -0
  242. package/src/lib/philosophy-toolkit.ts +75 -0
  243. package/src/lib/pipeline.orig.ts +659 -0
  244. package/src/lib/pipeline.ts +42 -0
  245. package/src/lib/precache.ts +128 -0
  246. package/src/lib/py-sandbox.ts +205 -0
  247. package/src/lib/quality-score.ts +96 -0
  248. package/src/lib/quant-engine.ts +231 -0
  249. package/src/lib/quant-lib.ts +80 -0
  250. package/src/lib/reportos.ts +175 -0
  251. package/src/lib/research-os.ts +306 -0
  252. package/src/lib/resource-estimator.ts +114 -0
  253. package/src/lib/rpm-governor.ts +93 -0
  254. package/src/lib/runtime-estimator.ts +135 -0
  255. package/src/lib/sage/empty-space-v6.ts +560 -0
  256. package/src/lib/sage/empty-space-v7.ts +222 -0
  257. package/src/lib/sage/empty-space.ts +733 -0
  258. package/src/lib/sage/engine.ts +786 -0
  259. package/src/lib/sage/index.ts +17 -0
  260. package/src/lib/sage/judge.ts +246 -0
  261. package/src/lib/sage/prng.ts +53 -0
  262. package/src/lib/sage/reality-grounding.ts +380 -0
  263. package/src/lib/sage/repetition.ts +151 -0
  264. package/src/lib/sage/saga-os-v2-engines.ts +1870 -0
  265. package/src/lib/sage/saga-os-v2.ts +274 -0
  266. package/src/lib/sage/saga-os-v3-core.ts +1491 -0
  267. package/src/lib/sage/saga-os-v3-release.ts +739 -0
  268. package/src/lib/sage/saga-os-v4-aureate.ts +1161 -0
  269. package/src/lib/sage/saga-os-v4.ts +212 -0
  270. package/src/lib/sage/saga-os-v5.ts +205 -0
  271. package/src/lib/sage/saga-os-v6.ts +346 -0
  272. package/src/lib/sage/saga-os-v7.ts +314 -0
  273. package/src/lib/sage/saga-os-v8.ts +505 -0
  274. package/src/lib/sage/saga-os.ts +329 -0
  275. package/src/lib/sage/taxonomy.ts +403 -0
  276. package/src/lib/sage/unified-roll.ts +524 -0
  277. package/src/lib/sage/worked-sketches.ts +44 -0
  278. package/src/lib/sage.ts +166 -0
  279. package/src/lib/scraper-debug-bus.ts +53 -0
  280. package/src/lib/scraper-enhanced.orig.ts +153 -0
  281. package/src/lib/scraper-enhanced.ts +10 -0
  282. package/src/lib/scraper-hardener.base.orig.ts +155 -0
  283. package/src/lib/scraper-hardener.base.ts +317 -0
  284. package/src/lib/scraper-hardener.ts +1 -0
  285. package/src/lib/scraper-palisade/palisade-adjudicator.orig.ts +419 -0
  286. package/src/lib/scraper-palisade/palisade-adjudicator.ts +13 -0
  287. package/src/lib/scraper-vnext/arbiter-omega.orig.ts +688 -0
  288. package/src/lib/scraper-vnext/arbiter-omega.ts +13 -0
  289. package/src/lib/scraper-vnext/canonical-portfolio-augments.ts +479 -0
  290. package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.orig.ts +1529 -0
  291. package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.ts +13 -0
  292. package/src/lib/scraper-vnext/conclave-omega.ts +1830 -0
  293. package/src/lib/scraper-vnext/content-extractor-v2.ts +226 -0
  294. package/src/lib/scraper-vnext/diagnostics-suite.ts +36 -0
  295. package/src/lib/scraper-vnext/epistemic-packer.ts +97 -0
  296. package/src/lib/scraper-vnext/fusion-v2.ts +65 -0
  297. package/src/lib/scraper-vnext/hydra-reader.orig.ts +1216 -0
  298. package/src/lib/scraper-vnext/hydra-reader.ts +13 -0
  299. package/src/lib/scraper-vnext/native-scraper-browser-vnext.orig.ts +91 -0
  300. package/src/lib/scraper-vnext/native-scraper-browser-vnext.ts +13 -0
  301. package/src/lib/scraper-vnext/nexus-consensus.orig.ts +905 -0
  302. package/src/lib/scraper-vnext/nexus-consensus.ts +13 -0
  303. package/src/lib/scraper-vnext/portfolio-consensus-adjudicator.ts +804 -0
  304. package/src/lib/scraper-vnext/portfolio-consensus-memory.ts +377 -0
  305. package/src/lib/scraper-vnext/portfolio-terminal-governor.ts +548 -0
  306. package/src/lib/scraper-vnext/query-strategist.orig.ts +224 -0
  307. package/src/lib/scraper-vnext/query-strategist.ts +423 -0
  308. package/src/lib/scraper-vnext/retrieval-accelerator.ts +708 -0
  309. package/src/lib/scraper-vnext/retrieval-audit-augments.ts +477 -0
  310. package/src/lib/scraper-vnext/retrieval-control-plane.ts +904 -0
  311. package/src/lib/scraper-vnext/retrieval-policy-augments.ts +358 -0
  312. package/src/lib/scraper-vnext/safe-fetch-v2.ts +157 -0
  313. package/src/lib/scraper-vnext/sentinel-omega.ts +56 -0
  314. package/src/lib/scraper-vnext/sentinel-orchestrator.ts +69 -0
  315. package/src/lib/scraper-vnext/sibyl-oracle.orig.ts +413 -0
  316. package/src/lib/scraper-vnext/sibyl-oracle.ts +13 -0
  317. package/src/lib/scraper-vnext/smart-read-v2.ts +55 -0
  318. package/src/lib/scraper-vnext/spa-rescue-bridge.ts +608 -0
  319. package/src/lib/scraper-vnext/strata-engine.orig.ts +2666 -0
  320. package/src/lib/scraper-vnext/strata-engine.ts +13 -0
  321. package/src/lib/scraper-vnext/structured-source-adapter.orig.ts +369 -0
  322. package/src/lib/scraper-vnext/structured-source-adapter.ts +34 -0
  323. package/src/lib/scraper-vnext/terminal-complete.ts +224 -0
  324. package/src/lib/scraper-vnext/terminal-final.ts +277 -0
  325. package/src/lib/scraper-vnext/terminal-saturation.ts +345 -0
  326. package/src/lib/scraper-vnext/terminal-wire.ts +425 -0
  327. package/src/lib/scraper-vnext/vanguard-titanium.orig.ts +467 -0
  328. package/src/lib/scraper-vnext/vanguard-titanium.ts +17 -0
  329. package/src/lib/search-cache.ts +138 -0
  330. package/src/lib/sloop-runner.base.ts +223 -0
  331. package/src/lib/sloop-runner.ts +104 -0
  332. package/src/lib/sloop.ts +114 -0
  333. package/src/lib/small-model-adapters.ts +82 -0
  334. package/src/lib/sscp.ts +86 -0
  335. package/src/lib/system-map.ts +54 -0
  336. package/src/lib/uni-node.ts +86 -0
  337. package/src/lib/universal-rigor-guard.ts +433 -0
  338. package/src/lib/v15-gate-testbed.ts +274 -0
  339. package/src/lib/v15-gemini.base.ts +89 -0
  340. package/src/lib/v15-gemini.ts +1 -0
  341. package/src/lib/v15-grounding.orig.ts +241 -0
  342. package/src/lib/v15-grounding.ts +79 -0
  343. package/src/lib/v15-pipeline.base.ts +769 -0
  344. package/src/lib/v15-pipeline.orig.ts +1154 -0
  345. package/src/lib/v15-pipeline.ts +674 -0
  346. package/src/lib/v15-questions.ts +64 -0
  347. package/src/lib/v15-rate-limiter.orig.ts +91 -0
  348. package/src/lib/v15-rate-limiter.ts +48 -0
  349. package/src/lib/v15-state.base.ts +87 -0
  350. package/src/lib/v15-state.ts +28 -0
  351. package/src/lib/visual-table-generator.tsx +207 -0
  352. package/src/lib/wasm-runtime.ts +133 -0
  353. package/src/lib/williams-persona-guide.ts +265 -0
  354. package/src/lib/williams-style.base.ts +464 -0
  355. package/src/lib/williams-style.ts +59 -0
  356. package/src/lib/worker-pool.ts +96 -0
  357. package/src/lib/writing-tiers.ts +125 -0
  358. package/src/main.orig.tsx +10 -0
  359. package/src/main.tsx +10 -0
  360. package/src/utils/cn.orig.ts +6 -0
  361. package/src/utils/cn.ts +6 -0
  362. package/src/vite-env.d.ts +1 -0
  363. package/tsconfig.json +31 -0
  364. package/unify.mjs +537 -0
  365. package/vite.config.ts +18 -0
@@ -0,0 +1,306 @@
1
+ /**
2
+ * ResearchOS v6 — Academic Research & NIH Grant Engine
3
+ *
4
+ * Provides:
5
+ * 1. Claim type taxonomy (OBS/DERIV/ASSUMP/HYP/THEORY/METHOD/RESULT/INTERP/LIMIT/REC/NORM)
6
+ * 2. NIH mechanism metadata (R01/R03/R15/R21 with page limits, budgets, review factors)
7
+ * 3. Study-design modules with reporting-standard mappings
8
+ * 4. Reviewer-vulnerability heuristic scoring
9
+ * 5. Reporting-standard selector (PRISMA/CONSORT/STROBE/COREQ/APA JARS)
10
+ * 6. Research gap taxonomy
11
+ * 7. Manuscript readiness score
12
+ *
13
+ * All scoring functions are heuristic engineering estimates, not official NIH formulas.
14
+ */
15
+
16
+ // ─── Claim types ────────────────────────────────────────────────────
17
+ export type ClaimType =
18
+ | "OBS" // observed fact / literature claim
19
+ | "DERIV" // statistical / mathematical derivation
20
+ | "ASSUMP" // explicit assumption
21
+ | "HYP" // hypothesis
22
+ | "THEORY" // theoretical proposition
23
+ | "METHOD" // methodological choice
24
+ | "RESULT" // empirical finding
25
+ | "INTERP" // interpretation of results
26
+ | "LIMIT" // limitation
27
+ | "REC" // recommendation
28
+ | "NORM"; // normative / philosophical claim
29
+
30
+ export const CLAIM_TYPE_LABELS: Record<ClaimType, string> = {
31
+ OBS: "Observed fact / literature claim",
32
+ DERIV: "Statistical / mathematical derivation",
33
+ ASSUMP: "Explicit assumption",
34
+ HYP: "Hypothesis",
35
+ THEORY: "Theoretical proposition",
36
+ METHOD: "Methodological choice",
37
+ RESULT: "Empirical finding",
38
+ INTERP: "Interpretation of results",
39
+ LIMIT: "Limitation",
40
+ REC: "Recommendation",
41
+ NORM: "Normative / philosophical claim",
42
+ };
43
+
44
+ // ─── NIH Mechanisms ─────────────────────────────────────────────────
45
+ export interface NIHMechanism {
46
+ code: string;
47
+ name: string;
48
+ researchStrategyPages: number;
49
+ budgetAnchor: string;
50
+ duration: string;
51
+ reviewFactors: string[];
52
+ bestFor: string;
53
+ fatalFlaws: string[];
54
+ }
55
+
56
+ export const NIH_MECHANISMS: NIHMechanism[] = [
57
+ {
58
+ code: "R01",
59
+ name: "Research Project Grant",
60
+ researchStrategyPages: 12,
61
+ budgetAnchor: "Generally not capped; must reflect actual project needs",
62
+ duration: "1-5 budget periods",
63
+ reviewFactors: [
64
+ "Factor 1: Importance of the Research (Significance + Innovation, scored 1-9)",
65
+ "Factor 2: Rigor and Feasibility (Approach, scored 1-9)",
66
+ "Factor 3: Expertise and Resources (Investigator + Environment, sufficient/gaps)",
67
+ ],
68
+ bestFor: "Full independent project with strong premise and sustained impact",
69
+ fatalFlaws: [
70
+ "No central hypothesis",
71
+ "No rigorous prior-research assessment",
72
+ "No power/precision/sample justification",
73
+ "No alternatives for risky steps",
74
+ "Aims are dependent dominoes (if Aim 1 fails, whole project collapses)",
75
+ "Team expertise gap unpatched",
76
+ ],
77
+ },
78
+ {
79
+ code: "R03",
80
+ name: "Small Research Grant",
81
+ researchStrategyPages: 6,
82
+ budgetAnchor: "Up to $50,000 direct costs/year, up to 2 years, nonrenewable",
83
+ duration: "Up to 2 years",
84
+ reviewFactors: [
85
+ "Factor 1: Importance (smaller scope, tight focus)",
86
+ "Factor 2: Rigor and Feasibility",
87
+ "Factor 3: Expertise and Resources",
88
+ ],
89
+ bestFor: "Small, self-contained project: pilot/feasibility, secondary analysis, methods development",
90
+ fatalFlaws: [
91
+ "Looks like a compressed R01 instead of a self-contained project",
92
+ "Scope exceeds 2-year / $50K/yr reality",
93
+ "No clear finish line or next-step logic",
94
+ ],
95
+ },
96
+ {
97
+ code: "R15",
98
+ name: "Research Enhancement Award (AREA/REAP)",
99
+ researchStrategyPages: 12,
100
+ budgetAnchor: "Modular/R&R thresholds; project period limited to 3 years",
101
+ duration: "Up to 3 years",
102
+ reviewFactors: [
103
+ "Factor 1: Importance of the Research",
104
+ "Factor 2: Rigor and Feasibility",
105
+ "Factor 3: Expertise, Resources, AND student involvement + institutional strengthening",
106
+ ],
107
+ bestFor: "Meritorious research at eligible institutions; student exposure to research",
108
+ fatalFlaws: [
109
+ "Student involvement is decorative rather than operational",
110
+ "PI eligibility conflicts not addressed",
111
+ "Institutional eligibility letter missing or weak",
112
+ "Too ambitious for a 3-year R15",
113
+ "Student training plan not connected to scientific milestones",
114
+ ],
115
+ },
116
+ {
117
+ code: "R21",
118
+ name: "Exploratory / Developmental Grant",
119
+ researchStrategyPages: 6,
120
+ budgetAnchor: "Up to $275,000 total direct costs over 2 years; no more than $200,000 in any one year",
121
+ duration: "Up to 2 years, nonrenewable",
122
+ reviewFactors: [
123
+ "Factor 1: Importance and Innovation (must justify uncertainty)",
124
+ "Factor 2: Rigor and Feasibility",
125
+ "Factor 3: Expertise and Resources",
126
+ ],
127
+ bestFor: "High-risk/high-reward, feasibility, novel direction",
128
+ fatalFlaws: [
129
+ "Uncertainty is not scientifically justified (application is simply underdeveloped)",
130
+ "No clear stopping rules",
131
+ "No logic connecting R21 output to R01-scale work",
132
+ ],
133
+ },
134
+ ];
135
+
136
+ // ─── Study designs + reporting standard mapping ─────────────────────
137
+ export interface StudyDesign {
138
+ id: string;
139
+ name: string;
140
+ category: "quantitative" | "qualitative" | "mixed" | "review" | "theoretical";
141
+ reportingStandards: string[];
142
+ reviewerAttacks: string[];
143
+ }
144
+
145
+ export const STUDY_DESIGNS: StudyDesign[] = [
146
+ { id: "rct", name: "Randomized Controlled Trial", category: "quantitative",
147
+ reportingStandards: ["CONSORT 2025"],
148
+ reviewerAttacks: ["Internal validity is weak", "Manipulation does not isolate mechanism"] },
149
+ { id: "observational", name: "Observational (Cohort/Case-Control/Cross-Sectional)", category: "quantitative",
150
+ reportingStandards: ["STROBE"],
151
+ reviewerAttacks: ["Causal language exceeds design", "Confounders not adequately controlled"] },
152
+ { id: "quasi-experimental", name: "Quasi-Experimental (DID/RD/ITS/IV)", category: "quantitative",
153
+ reportingStandards: ["APA JARS-Quant"],
154
+ reviewerAttacks: ["Identification assumptions are not credible"] },
155
+ { id: "survey", name: "Survey / Cross-Sectional", category: "quantitative",
156
+ reportingStandards: ["APA JARS-Quant", "STROBE"],
157
+ reviewerAttacks: ["Common method variance", "Self-selection bias"] },
158
+ { id: "sem", name: "Structural Equation Modeling", category: "quantitative",
159
+ reportingStandards: ["APA JARS-Quant"],
160
+ reviewerAttacks: ["Model fit acceptable but theory underidentified", "Measurement invariance not tested"] },
161
+ { id: "grounded-theory", name: "Grounded Theory", category: "qualitative",
162
+ reportingStandards: ["COREQ", "SRQR"],
163
+ reviewerAttacks: ["This is thematic analysis mislabeled as grounded theory"] },
164
+ { id: "thematic-analysis", name: "Reflexive Thematic Analysis", category: "qualitative",
165
+ reportingStandards: ["COREQ", "SRQR", "APA JARS-Qual"],
166
+ reviewerAttacks: ["Themes are topic summaries, not analytic themes"] },
167
+ { id: "phenomenology", name: "Phenomenology / IPA", category: "qualitative",
168
+ reportingStandards: ["COREQ"],
169
+ reviewerAttacks: ["Analysis is descriptive but not phenomenological"] },
170
+ { id: "ethnography", name: "Ethnography", category: "qualitative",
171
+ reportingStandards: ["COREQ"],
172
+ reviewerAttacks: ["Field engagement is too thin"] },
173
+ { id: "case-study", name: "Case Study", category: "qualitative",
174
+ reportingStandards: ["COREQ"],
175
+ reviewerAttacks: ["Case is not bounded or theoretically justified"] },
176
+ { id: "systematic-review", name: "Systematic Review / Meta-Analysis", category: "review",
177
+ reportingStandards: ["PRISMA 2020"],
178
+ reviewerAttacks: ["Search strategy is not reproducible", "Risk of bias not assessed"] },
179
+ { id: "mixed-convergent", name: "Mixed Methods (Convergent Parallel)", category: "mixed",
180
+ reportingStandards: ["APA JARS-Mixed", "MMAT"],
181
+ reviewerAttacks: ["Integration is decorative not substantive"] },
182
+ { id: "mixed-explanatory", name: "Mixed Methods (Explanatory Sequential)", category: "mixed",
183
+ reportingStandards: ["APA JARS-Mixed"],
184
+ reviewerAttacks: ["Qual strand does not explain the quant finding"] },
185
+ { id: "philosophy", name: "Philosophy / Theory Paper", category: "theoretical",
186
+ reportingStandards: [],
187
+ reviewerAttacks: ["Argument contains a hidden premise", "Counterexample not addressed"] },
188
+ ];
189
+
190
+ // ─── Reviewer Vulnerability Heuristic ───────────────────────────────
191
+ export interface VulnerabilityInput {
192
+ importanceGap: number; // 0-1
193
+ methodsGap: number; // 0-1
194
+ measurementGap: number; // 0-1
195
+ theoryGap: number; // 0-1
196
+ powerSampleGap: number; // 0-1
197
+ reproducibilityGap: number; // 0-1
198
+ writingClarityGap: number; // 0-1
199
+ }
200
+
201
+ export function reviewerVulnerability(input: VulnerabilityInput): { score: number; level: string } {
202
+ const score =
203
+ 0.25 * input.importanceGap +
204
+ 0.20 * input.methodsGap +
205
+ 0.15 * input.measurementGap +
206
+ 0.15 * input.theoryGap +
207
+ 0.10 * input.powerSampleGap +
208
+ 0.10 * input.reproducibilityGap +
209
+ 0.05 * input.writingClarityGap;
210
+ const level =
211
+ score <= 0.20 ? "Low vulnerability" :
212
+ score <= 0.40 ? "Moderate vulnerability" :
213
+ score <= 0.60 ? "Serious revision risk" :
214
+ "Likely rejection / poor grant score";
215
+ return { score, level };
216
+ }
217
+
218
+ // ─── NIH Impact Heuristic ───────────────────────────────────────────
219
+ export function nihImpactHeuristic(
220
+ importance: number, // 1 exceptional - 9 poor
221
+ rigorFeasibility: number, // 1 exceptional - 9 poor
222
+ resourcesGate: 0 | 1 | 2, // 0 sufficient, 1 minor gaps, 2 major gaps
223
+ humanSubjectsRisk = 0,
224
+ biohazardRisk = 0,
225
+ budgetConcern = 0,
226
+ ): { score: number; label: string } {
227
+ const resourcePenalty = [0, 0.5, 1.5][resourcesGate];
228
+ const compliancePenalty = humanSubjectsRisk + biohazardRisk + budgetConcern;
229
+ const raw = 0.45 * importance + 0.45 * rigorFeasibility + resourcePenalty + compliancePenalty;
230
+ const score = Math.min(9, Math.max(1, raw));
231
+ const label =
232
+ score <= 2 ? "Exceptional" :
233
+ score <= 3.5 ? "Outstanding" :
234
+ score <= 5 ? "Good" :
235
+ score <= 7 ? "Fair" :
236
+ "Poor";
237
+ return { score, label };
238
+ }
239
+
240
+ // ─── Manuscript Readiness Score ──────────────────────────────────────
241
+ export function manuscriptReadiness(i: {
242
+ contributionStrength: number; // 0-1
243
+ methodsRigor: number; // 0-1
244
+ theoryFit: number; // 0-1
245
+ reportingCompliance: number; // 0-1
246
+ reproducibility: number; // 0-1
247
+ writingClarity: number; // 0-1
248
+ reviewerResilience: number; // 0-1
249
+ }): { score: number; label: string } {
250
+ const score =
251
+ 0.20 * i.contributionStrength +
252
+ 0.20 * i.methodsRigor +
253
+ 0.15 * i.theoryFit +
254
+ 0.15 * i.reportingCompliance +
255
+ 0.10 * i.reproducibility +
256
+ 0.10 * i.writingClarity +
257
+ 0.10 * i.reviewerResilience;
258
+ const label =
259
+ score >= 0.80 ? "Ready to submit" :
260
+ score >= 0.60 ? "Needs minor revision" :
261
+ score >= 0.40 ? "Needs major revision" :
262
+ "Not ready";
263
+ return { score, label };
264
+ }
265
+
266
+ // ─── Research Gap Taxonomy ──────────────────────────────────────────
267
+ export const RESEARCH_GAPS = [
268
+ { id: "empirical", name: "Empirical Gap", desc: "No data on a population, setting, period, or outcome" },
269
+ { id: "theoretical", name: "Theoretical Gap", desc: "Existing theories cannot explain a pattern" },
270
+ { id: "measurement", name: "Measurement Gap", desc: "Construct is poorly operationalized" },
271
+ { id: "method", name: "Method Gap", desc: "Existing designs cannot support the needed inference" },
272
+ { id: "mechanism", name: "Mechanism Gap", desc: "Relationship observed but process unknown" },
273
+ { id: "translational", name: "Translational Gap", desc: "Discovery exists but is not implemented" },
274
+ { id: "equity", name: "Equity Gap", desc: "Populations or contexts excluded from evidence base" },
275
+ { id: "replication", name: "Replication Gap", desc: "Claims depend on single, fragile, or underpowered studies" },
276
+ { id: "synthesis", name: "Synthesis Gap", desc: "Literature exists but has not been integrated" },
277
+ ];
278
+
279
+ // ─── Reporting Standard Selector (deterministic) ────────────────────
280
+ export function selectReportingStandards(design: {
281
+ reviewType?: string;
282
+ intervention?: string;
283
+ designType?: string;
284
+ qualitative?: boolean;
285
+ mixedMethods?: boolean;
286
+ field?: string;
287
+ }): string[] {
288
+ const standards: string[] = [];
289
+ if (design.reviewType === "systematic_review" || design.reviewType === "meta_analysis") standards.push("PRISMA 2020");
290
+ if (design.intervention === "randomized_trial") standards.push("CONSORT 2025");
291
+ if (["cohort", "case_control", "cross_sectional"].includes(design.designType ?? "")) standards.push("STROBE");
292
+ if (design.qualitative) standards.push("COREQ", "SRQR");
293
+ if (design.mixedMethods) standards.push("APA JARS-Mixed", "MMAT");
294
+ if (["psychology", "behavioral_science", "social_science", "education"].includes(design.field ?? "")) standards.push("APA JARS");
295
+ return [...new Set(standards)];
296
+ }
297
+
298
+ // ─── Reviewer Persona Definitions ───────────────────────────────────
299
+ export const REVIEWER_PERSONAS = [
300
+ { id: "theory", name: "Theory Reviewer", focus: "Conceptual contribution, construct definitions, theory-hypothesis link" },
301
+ { id: "methods", name: "Methods Reviewer", focus: "Design-inference match, sampling, models, robustness" },
302
+ { id: "domain", name: "Field/Domain Reviewer", focus: "Literature currency, citation fairness, practical contribution" },
303
+ { id: "statistician", name: "Skeptical Statistician", focus: "Power, assumptions, multiplicity, null interpretation" },
304
+ { id: "qualitative", name: "Qualitative Rigor Reviewer", focus: "Epistemology, reflexivity, data grounding, transferability" },
305
+ { id: "ethics", name: "Ethics/Open Science Reviewer", focus: "IRB/consent, DMS plan, preregistration, COI" },
306
+ ];
@@ -0,0 +1,114 @@
1
+ import { TIERS } from "./gbse/tiers";
2
+
3
+ export type DriverId =
4
+ | "frontier"
5
+ | "gemma4-31b"
6
+ | "qwen3.6"
7
+ | "gemma4-e4b"
8
+ | "apple-ondevice"
9
+ | "bonsai-8b";
10
+
11
+ export interface EstimateInput {
12
+ query: string;
13
+ tier: number;
14
+ driver: DriverId;
15
+ anchorMode: "required" | "preferred" | "off";
16
+ webAccess: "on" | "trusted" | "off";
17
+ verifierAlpha: number;
18
+ councilWidth: number;
19
+ workerDepth: number;
20
+ }
21
+
22
+ export interface Estimate {
23
+ tier: number;
24
+ time_s: number;
25
+ tokens_in: number;
26
+ tokens_out: number;
27
+ tools: number;
28
+ paths: number;
29
+ states: number;
30
+ ram_bytes: number;
31
+ dense_states_avoided: number;
32
+ dense_bytes_avoided: number;
33
+ coverage: number;
34
+ }
35
+
36
+ export interface Actuals {
37
+ actual_in: number;
38
+ actual_out: number;
39
+ actual_tools: number;
40
+ actual_paths: number;
41
+ actual_states: number;
42
+ actual_ram: number;
43
+ entropy: number;
44
+ contradictions: number;
45
+ token_saved: number;
46
+ }
47
+
48
+ const DRIVER_MULTIPLIER: Record<DriverId, { time: number; tokens: number; coverage: number }> = {
49
+ frontier: { time: 0.8, tokens: 1.0, coverage: 1.02 },
50
+ "gemma4-31b": { time: 1.0, tokens: 1.0, coverage: 1.0 },
51
+ "qwen3.6": { time: 1.25, tokens: 1.12, coverage: 1.0 },
52
+ "gemma4-e4b": { time: 1.8, tokens: 0.78, coverage: 0.88 },
53
+ "apple-ondevice": { time: 2.0, tokens: 0.65, coverage: 0.82 },
54
+ "bonsai-8b": { time: 2.3, tokens: 0.55, coverage: 0.78 },
55
+ };
56
+
57
+ export function estimateResources(input: EstimateInput): Estimate {
58
+ const tier = Math.max(0, Math.min(5, input.tier));
59
+ const spec = TIERS[tier];
60
+ const words = input.query.trim().split(/\s+/).filter(Boolean).length;
61
+ const complexity = Math.min(2.0, 0.65 + words / 80 + input.councilWidth / 40 + input.workerDepth / 60);
62
+ const driver = DRIVER_MULTIPLIER[input.driver];
63
+ const anchorDiscount = input.anchorMode === "required" ? 0.72 : input.anchorMode === "preferred" ? 0.86 : 1.0;
64
+ const webMultiplier = input.webAccess === "off" ? 0.35 : input.webAccess === "trusted" ? 0.75 : 1.0;
65
+ const verifierBoost = 1 + Math.max(0, input.verifierAlpha - 0.2) * 0.9;
66
+
67
+ const tokens = spec.maxTokens * 0.32 * complexity * driver.tokens * anchorDiscount * verifierBoost;
68
+ const tokens_in = Math.round(tokens * 0.68);
69
+ const tokens_out = Math.round(tokens * 0.32);
70
+ const tools = Math.max(0, Math.round(spec.evidenceProbes * complexity * webMultiplier + (input.anchorMode === "off" ? 0 : 6)));
71
+ const paths = Math.max(1, Math.round(input.councilWidth * Math.max(1, input.workerDepth / 3)));
72
+ const states = Math.max(1, Math.round(paths * (tier + 1) * 1.7));
73
+ const sparseEdges = Math.max(1, tools + paths * 3 + states);
74
+ const ram_bytes = sparseEdges * 64;
75
+ const dense_states_avoided = Math.pow(2, Math.min(20, Math.max(1, states)));
76
+ const dense_bytes_avoided = dense_states_avoided * 8;
77
+ const coverage = Math.max(
78
+ 0.15,
79
+ Math.min(0.98, spec.forecastCoverage * driver.coverage * (input.anchorMode === "required" ? 0.96 : 1) * (input.webAccess === "off" ? 0.78 : 1)),
80
+ );
81
+ const time_s = Math.round(spec.maxSeconds * 0.45 * complexity * driver.time * webMultiplier * verifierBoost);
82
+
83
+ return { tier, time_s, tokens_in, tokens_out, tools, paths, states, ram_bytes, dense_states_avoided, dense_bytes_avoided, coverage };
84
+ }
85
+
86
+ /** Honest empty actuals when no run has occurred. No simulation — zeros mean "not measured yet". */
87
+ export function zeroActuals(): Actuals {
88
+ return {
89
+ actual_in: 0, actual_out: 0, actual_tools: 0, actual_paths: 0,
90
+ actual_states: 0, actual_ram: 0, entropy: 0, contradictions: 0, token_saved: 0,
91
+ };
92
+ }
93
+
94
+ export function aegisPanel(est: Estimate, actual: Actuals, elapsed: number): string {
95
+ const d = (a: number, e: number) => `${a >= e ? "+" : ""}${a - e}`;
96
+ const densePower = Math.floor(Math.log2(Math.max(1, est.dense_states_avoided)));
97
+ return [
98
+ "╔════════════════════════════════════════════════════════════════════╗",
99
+ `║ AEGIS-PHI :: T${est.tier} ${TIERS[est.tier].name.padEnd(14)} :: live ${elapsed.toFixed(1).padStart(6)}s ║`,
100
+ "╠════════════════════════════════════════════════════════════════════╣",
101
+ `║ TIME est ${String(est.time_s).padStart(7)}s act ${elapsed.toFixed(1).padStart(8)}s Δ ${(elapsed - est.time_s).toFixed(0).padStart(7)} ║`,
102
+ `║ TOK IN est ${String(est.tokens_in).padStart(8)} act ${String(actual.actual_in).padStart(8)} Δ ${d(actual.actual_in, est.tokens_in).padStart(7)} ║`,
103
+ `║ TOK OUT est ${String(est.tokens_out).padStart(8)} act ${String(actual.actual_out).padStart(8)} Δ ${d(actual.actual_out, est.tokens_out).padStart(7)} ║`,
104
+ `║ TOOLS est ${String(est.tools).padStart(8)} act ${String(actual.actual_tools).padStart(8)} Δ ${d(actual.actual_tools, est.tools).padStart(7)} ║`,
105
+ `║ PATHS est ${String(est.paths).padStart(8)} act ${String(actual.actual_paths).padStart(8)} Δ ${d(actual.actual_paths, est.paths).padStart(7)} ║`,
106
+ `║ STATES est ${String(est.states).padStart(8)} act ${String(actual.actual_states).padStart(8)} Δ ${d(actual.actual_states, est.states).padStart(7)} ║`,
107
+ `║ RAM sparse est ${String(est.ram_bytes).padStart(8)}B act ${String(actual.actual_ram).padStart(8)}B ║`,
108
+ `║ DENSE AVOIDED 2^${densePower} mask = ${(est.dense_bytes_avoided / 1024).toFixed(1).padStart(7)} KB ║`,
109
+ `║ TOK SAVED via collapse vs raw fan-in: ${String(actual.token_saved).padStart(8)} ║`,
110
+ `║ PSI-ENTROPY ${actual.entropy.toFixed(3)} CONTRADICTIONS ${String(actual.contradictions).padStart(3)} ║`,
111
+ `║ COVERAGE forecast ${(est.coverage * 100).toFixed(1).padStart(5)}% ║`,
112
+ "╚════════════════════════════════════════════════════════════════════╝",
113
+ ].join("\n");
114
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * RPM Governor — serializes and throttles LLM calls so we never exceed the
3
+ * free-tier requests-per-minute ceiling (typically 5–15 RPM on this key).
4
+ *
5
+ * Strategy:
6
+ * - A single global queue spaces calls by (60000 / rpm) ms minimum interval.
7
+ * - Callers can batch multiple logical sub-prompts into ONE request via
8
+ * `batchPrompts()` so the N-Deep engine consumes one RPM slot, not N.
9
+ */
10
+
11
+ let lastCallTs = 0;
12
+ let chain: Promise<void> = Promise.resolve();
13
+
14
+ export interface ThrottleOpts {
15
+ rpm?: number;
16
+ onWait?: (ms: number) => void;
17
+ }
18
+
19
+ /** Run `fn` on a serialized chain, spacing calls to respect the RPM ceiling.
20
+ * FIXED: chain cannot deadlock — every link resolves to void regardless of fn outcome. */
21
+ export function throttle<T>(fn: () => Promise<T>, opts?: ThrottleOpts): Promise<T> {
22
+ const rpm = Math.max(1, opts?.rpm ?? 10);
23
+ const minInterval = Math.ceil(60_000 / rpm);
24
+ return new Promise<T>((resolve, reject) => {
25
+ chain = chain.then(async () => {
26
+ const now = Date.now();
27
+ const wait = Math.max(0, lastCallTs + minInterval - now);
28
+ if (wait > 0) {
29
+ opts?.onWait?.(wait);
30
+ await new Promise((r) => setTimeout(r, wait));
31
+ }
32
+ lastCallTs = Date.now();
33
+ try {
34
+ resolve(await fn());
35
+ } catch (e) {
36
+ reject(e);
37
+ }
38
+ }, () => {
39
+ // prior link rejected — still execute this link
40
+ lastCallTs = Date.now();
41
+ fn().then(resolve, reject);
42
+ });
43
+ });
44
+ }
45
+
46
+ /** Reset the throttle chain — call between runs to prevent stale state. */
47
+ export function resetThrottle(): void {
48
+ chain = Promise.resolve();
49
+ lastCallTs = 0;
50
+ }
51
+
52
+ export interface BatchSection {
53
+ key: string; // stable id the model must echo back
54
+ prompt: string; // the sub-task
55
+ }
56
+
57
+ /**
58
+ * Compose several sub-tasks into ONE prompt that asks the model to return a
59
+ * single JSON object keyed by section id. This collapses N requests into 1,
60
+ * which is the difference between staying under 5 RPM and tripping it.
61
+ */
62
+ export function batchPrompts(intro: string, sections: BatchSection[]): string {
63
+ const blocks = sections
64
+ .map((s, i) => `### TASK ${i + 1} — key "${s.key}"\n${s.prompt}`)
65
+ .join("\n\n");
66
+ const keys = sections.map((s) => `"${s.key}"`).join(", ");
67
+ return `${intro}
68
+
69
+ You will answer ${sections.length} tasks in ONE reply to conserve rate limit.
70
+ Return a SINGLE raw JSON object whose keys are exactly: ${keys}.
71
+ Each value is a string containing that task's full answer. No prose outside the JSON.
72
+
73
+ ${blocks}`;
74
+ }
75
+
76
+ /** Parse a batched JSON reply back into a key→answer map (best-effort). */
77
+ export function parseBatchReply(raw: string, keys: string[]): Record<string, string> {
78
+ const out: Record<string, string> = {};
79
+ let json: any = null;
80
+ const fenced = raw.match(/```(?:json)?\s*([\s\S]*?)```/i);
81
+ const src = fenced ? fenced[1] : raw;
82
+ const start = src.indexOf("{");
83
+ const end = src.lastIndexOf("}");
84
+ if (start !== -1 && end > start) {
85
+ try { json = JSON.parse(src.slice(start, end + 1)); } catch { /* */ }
86
+ }
87
+ for (const k of keys) {
88
+ if (json && typeof json[k] === "string") out[k] = json[k];
89
+ else if (json && json[k] != null) out[k] = JSON.stringify(json[k]);
90
+ else out[k] = "";
91
+ }
92
+ return out;
93
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Runtime Estimator — deterministic configuration estimator.
3
+ *
4
+ * Two estimators are exposed:
5
+ * 1. `estimateRuntime(simple)` — legacy minimal estimator (existing API).
6
+ * 2. `estimateRuntime(advanced)` — when called with the advanced input shape,
7
+ * breaks down per-phase wall-clock seconds for Grounding / SLOOP / N-Deep.
8
+ *
9
+ * Both are pure functions; no network, no LLM calls. Used by MemoryStressPanel
10
+ * to give users a time-budget preview before launching a heavy query.
11
+ */
12
+
13
+ export interface RuntimeEstimate {
14
+ estimatedSeconds: number;
15
+ llmCalls: number;
16
+ notes: string[];
17
+ /** Per-phase breakdown when advanced estimator is invoked. */
18
+ breakdown?: Array<{ step: string; seconds: number }>;
19
+ }
20
+
21
+ export interface RuntimeEstimateInput {
22
+ // Simple form (back-compat with prior callers)
23
+ pages?: number;
24
+ nDeep?: number;
25
+ cluster?: number;
26
+ searchDepth?: number;
27
+ // Advanced form (new)
28
+ sources?: number;
29
+ hypotheses?: number;
30
+ deepResearch?: boolean;
31
+ sloopPages?: number;
32
+ clusterWidth?: number;
33
+ nDeepPasses?: number;
34
+ forceSloop?: boolean;
35
+ modelFamily?: "gemini-fast" | "gemma-31b" | "other";
36
+ }
37
+
38
+ export function estimateRuntime(opts: RuntimeEstimateInput): RuntimeEstimate {
39
+ // ── Advanced path: triggered when any advanced field is provided ─────────
40
+ const isAdvanced =
41
+ opts.sources !== undefined ||
42
+ opts.hypotheses !== undefined ||
43
+ opts.forceSloop !== undefined ||
44
+ opts.modelFamily !== undefined ||
45
+ opts.deepResearch !== undefined ||
46
+ opts.sloopPages !== undefined ||
47
+ opts.clusterWidth !== undefined ||
48
+ opts.nDeepPasses !== undefined;
49
+
50
+ if (isAdvanced) {
51
+ const breakdown: Array<{ step: string; seconds: number }> = [];
52
+ const modelFamily = opts.modelFamily ?? "other";
53
+ const modelFactor = modelFamily === "gemma-31b" ? 1.8 : modelFamily === "gemini-fast" ? 1.0 : 1.25;
54
+
55
+ const sources = opts.sources ?? 18;
56
+ const hypotheses = opts.hypotheses ?? 4;
57
+ const sloopPages = opts.sloopPages ?? opts.pages ?? 8;
58
+ const clusterWidth = opts.clusterWidth ?? opts.cluster ?? 6;
59
+ const nDeepPasses = opts.nDeepPasses ?? opts.nDeep ?? 4;
60
+ const deepResearch = opts.deepResearch ?? false;
61
+ const forceSloop = opts.forceSloop ?? true;
62
+
63
+ // Grounding search wave: query + hypotheses. Cluster width batches.
64
+ const searchCalls = 1 + Math.max(0, hypotheses);
65
+ const effectiveCluster = Math.max(1, Math.min(clusterWidth, Math.max(1, hypotheses || 1)));
66
+ const searchSeconds = ((searchCalls * 4.2) / effectiveCluster + sources * 0.5) * modelFactor;
67
+ breakdown.push({ step: "Grounding", seconds: searchSeconds });
68
+
69
+ if (forceSloop) {
70
+ const sections = Math.max(4, sloopPages * 2);
71
+ const sloopSeconds = sections * 11.5 * modelFactor;
72
+ breakdown.push({ step: "SLOOP", seconds: sloopSeconds });
73
+ } else if (deepResearch) {
74
+ breakdown.push({ step: "4-Stage", seconds: 22 * modelFactor });
75
+ } else {
76
+ breakdown.push({ step: "Direct synthesis", seconds: 10 * modelFactor });
77
+ }
78
+
79
+ if (nDeepPasses > 0) {
80
+ // Each pass includes critique + section revisions + batched judge.
81
+ const nDeepSeconds = (nDeepPasses * 17 + 8) * modelFactor;
82
+ breakdown.push({ step: "N-Deep", seconds: nDeepSeconds });
83
+ }
84
+
85
+ const estimatedSeconds = Math.round(breakdown.reduce((sum, b) => sum + b.seconds, 0));
86
+ const llmCalls = Math.round(
87
+ (forceSloop ? Math.max(4, sloopPages * 2) : deepResearch ? 4 : 1) +
88
+ nDeepPasses * 3 + // critique + revisions + judge per pass
89
+ Math.max(0, hypotheses) // grounding
90
+ );
91
+ return {
92
+ estimatedSeconds: Math.max(12, estimatedSeconds),
93
+ llmCalls: Math.max(6, llmCalls),
94
+ notes: ["advanced", `model=${modelFamily}`, `pages=${sloopPages}`, `cluster=${clusterWidth}`, `nDeep=${nDeepPasses}`],
95
+ breakdown,
96
+ };
97
+ }
98
+
99
+ // ── Simple path: legacy estimator (back-compat) ──────────────────────────
100
+ const p = Math.max(4, Math.min(16, opts.pages ?? 8));
101
+ const nd = Math.max(1, Math.min(12, opts.nDeep ?? 4));
102
+ const c = Math.max(2, Math.min(20, opts.cluster ?? 8));
103
+ const d = Math.max(3, Math.min(12, opts.searchDepth ?? 5));
104
+
105
+ const llmCalls = Math.round(p * 1.4 + nd * 1.1 + (c * 0.6) + (d * 0.8));
106
+ const seconds = Math.round(p * 1.65 + nd * 2.0 + (c * 0.95) + (d * 1.05));
107
+
108
+ return {
109
+ estimatedSeconds: Math.max(12, seconds),
110
+ llmCalls: Math.max(6, llmCalls),
111
+ notes: ["heuristic", `pages=${p}`, `nDeep=${nd}`, `cluster=${c}`],
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Smoke test: verifies estimator produces sane output for the user-reported
117
+ * failing config (8 SLOOP / 4 N-Deep / 8 Cluster / 5 depth, 4-stage on).
118
+ * Used by MemoryStressPanel for at-load self-check.
119
+ */
120
+ export function runtimeEstimatorSmoke(): RuntimeEstimate {
121
+ const target = estimateRuntime({
122
+ sources: 18,
123
+ hypotheses: 4,
124
+ deepResearch: true,
125
+ forceSloop: true,
126
+ sloopPages: 8,
127
+ clusterWidth: 8,
128
+ nDeepPasses: 4,
129
+ modelFamily: "gemma-31b",
130
+ });
131
+ if (target.estimatedSeconds <= 0) throw new Error("runtime estimate must be positive");
132
+ if (!target.breakdown?.find(b => b.step === "SLOOP")) throw new Error("expected SLOOP step");
133
+ if (!target.breakdown?.find(b => b.step === "N-Deep")) throw new Error("expected N-Deep step");
134
+ return target;
135
+ }