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,215 @@
1
+ // ─── Deterministic Compute Sandbox ──────────────────────────────────────────
2
+ // A whitelisted function registry. The reasoning pipeline emits structured
3
+ // calculation requests (function id + numeric args); the sandbox executes the
4
+ // REAL pure-TypeScript quant functions and returns verified results.
5
+ //
6
+ // Safety properties (this is a reality-based engineering system):
7
+ // • No eval / no Function(): only pre-registered pure functions run.
8
+ // • Pure & side-effect-free: same inputs → same outputs, always.
9
+ // • Bounded: arg arrays are capped; non-finite results are flagged, not hidden.
10
+ // • Auditable: every call records {id, args, result, ok, error, ms}.
11
+ //
12
+ // The AI never computes numbers itself — it requests them and synthesizes the
13
+ // returned, verified values. This eliminates numeric hallucination.
14
+
15
+ import * as Q from "./quant-engine";
16
+
17
+ export interface ComputeSpec {
18
+ id: string; // registry key, e.g. "dcf_npv"
19
+ label: string; // human label
20
+ group: string; // grouping for UI/routing
21
+ params: { name: string; kind: "number" | "number[]"; default: number | number[] }[];
22
+ formula: string; // documentation
23
+ run: (args: Record<string, number | number[]>) => Record<string, number> | number;
24
+ }
25
+
26
+ const n = (v: unknown, d = 0): number => (typeof v === "number" && isFinite(v) ? v : d);
27
+ const arr = (v: unknown): number[] =>
28
+ Array.isArray(v) ? v.map((x) => Number(x)).filter((x) => isFinite(x)).slice(0, 512) : [];
29
+
30
+ // ─── The registry: every entry is a real, deterministic function ────────────
31
+ export const COMPUTE_REGISTRY: ComputeSpec[] = [
32
+ // Unit economics
33
+ { id: "ltv", label: "Lifetime Value", group: "Unit economics", formula: "(ARPU·GM)/churn",
34
+ params: [{ name: "arpuMonthly", kind: "number", default: 45 }, { name: "grossMargin", kind: "number", default: 0.78 }, { name: "churnMonthly", kind: "number", default: 0.02 }],
35
+ run: (a) => ({ ltv: Q.ltv(n(a.arpuMonthly), n(a.grossMargin), n(a.churnMonthly)) }) },
36
+ { id: "cac", label: "Customer Acquisition Cost", group: "Unit economics", formula: "S&M / new customers",
37
+ params: [{ name: "salesMarketing", kind: "number", default: 1_200_000 }, { name: "newCustomers", kind: "number", default: 400 }],
38
+ run: (a) => ({ cac: Q.cac(n(a.salesMarketing), n(a.newCustomers)) }) },
39
+ { id: "ltv_cac", label: "LTV : CAC ratio", group: "Unit economics", formula: "LTV / CAC (target > 3)",
40
+ params: [{ name: "ltv", kind: "number", default: 1755 }, { name: "cac", kind: "number", default: 3000 }],
41
+ run: (a) => ({ ratio: Q.ltvCacRatio(n(a.ltv), n(a.cac)) }) },
42
+ { id: "nrr", label: "Net Revenue Retention", group: "Unit economics", formula: "(start+exp−contr−churn)/start",
43
+ params: [{ name: "start", kind: "number", default: 1_000_000 }, { name: "expansion", kind: "number", default: 200_000 }, { name: "contraction", kind: "number", default: 50_000 }, { name: "churn", kind: "number", default: 80_000 }],
44
+ run: (a) => ({ nrr: Q.nrr(n(a.start), n(a.expansion), n(a.contraction), n(a.churn)) }) },
45
+ { id: "burn_multiple", label: "Burn Multiple", group: "Unit economics", formula: "net burn / net new ARR",
46
+ params: [{ name: "netBurn", kind: "number", default: 4_000_000 }, { name: "netNewARR", kind: "number", default: 3_000_000 }],
47
+ run: (a) => ({ burnMultiple: Q.burnMultiple(n(a.netBurn), n(a.netNewARR)) }) },
48
+ { id: "rule_of_40", label: "Rule of 40", group: "Unit economics", formula: "growth% + margin%",
49
+ params: [{ name: "growthPct", kind: "number", default: 60 }, { name: "marginPct", kind: "number", default: -15 }],
50
+ run: (a) => ({ ruleOf40: Q.ruleOf40(n(a.growthPct), n(a.marginPct)) }) },
51
+ { id: "months_runway", label: "Months of Runway", group: "Unit economics", formula: "cash / monthly burn",
52
+ params: [{ name: "cash", kind: "number", default: 24_000_000 }, { name: "monthlyBurn", kind: "number", default: 1_500_000 }],
53
+ run: (a) => ({ months: Q.monthsRunway(n(a.cash), n(a.monthlyBurn)) }) },
54
+
55
+ // Valuation
56
+ { id: "dcf_npv", label: "DCF / Enterprise Value", group: "Valuation", formula: "Σ CF/(1+r)^t + terminal",
57
+ params: [{ name: "cashFlows", kind: "number[]", default: [10, 12, 15, 18, 22] }, { name: "discountRate", kind: "number", default: 0.12 }, { name: "terminalGrowth", kind: "number", default: 0.02 }],
58
+ run: (a) => { const r = Q.dcfNpv(arr(a.cashFlows), n(a.discountRate, 0.12), n(a.terminalGrowth, 0.02)); return { enterpriseValue: r.enterpriseValue, pvCashFlows: r.pvCashFlows, pvTerminal: r.pvTerminal, terminalPctOfEV: r.terminalPctOfEV }; } },
59
+ { id: "irr", label: "Internal Rate of Return", group: "Valuation", formula: "rate s.t. NPV = 0",
60
+ params: [{ name: "cashFlows", kind: "number[]", default: [-100, 20, 30, 40, 60] }],
61
+ run: (a) => ({ irr: Q.irr(arr(a.cashFlows)) }) },
62
+ { id: "moic", label: "MOIC", group: "Valuation", formula: "exit / invested",
63
+ params: [{ name: "exit", kind: "number", default: 450 }, { name: "invested", kind: "number", default: 100 }],
64
+ run: (a) => ({ moic: Q.moic(n(a.exit), n(a.invested)) }) },
65
+ { id: "wacc", label: "WACC", group: "Valuation", formula: "wE·rE + wD·rD·(1−t)",
66
+ params: [{ name: "equityWeight", kind: "number", default: 0.7 }, { name: "costEquity", kind: "number", default: 0.12 }, { name: "debtWeight", kind: "number", default: 0.3 }, { name: "costDebt", kind: "number", default: 0.06 }, { name: "taxRate", kind: "number", default: 0.21 }],
67
+ run: (a) => ({ wacc: Q.wacc(n(a.equityWeight), n(a.costEquity), n(a.debtWeight), n(a.costDebt), n(a.taxRate)) }) },
68
+ { id: "capm", label: "CAPM cost of equity", group: "Valuation", formula: "rf + β·mrp",
69
+ params: [{ name: "riskFree", kind: "number", default: 0.043 }, { name: "beta", kind: "number", default: 1.2 }, { name: "marketPremium", kind: "number", default: 0.055 }],
70
+ run: (a) => ({ costEquity: Q.capm(n(a.riskFree), n(a.beta), n(a.marketPremium)) }) },
71
+ { id: "vc_premoney", label: "VC-method pre-money", group: "Valuation", formula: "PV(exit)·(1−dilution)",
72
+ params: [{ name: "exitValue", kind: "number", default: 1000 }, { name: "targetIRR", kind: "number", default: 0.35 }, { name: "years", kind: "number", default: 5 }, { name: "dilution", kind: "number", default: 0.2 }],
73
+ run: (a) => ({ preMoney: Q.vcMethodPreMoney(n(a.exitValue), n(a.targetIRR), n(a.years), n(a.dilution)) }) },
74
+
75
+ // Portfolio / fund
76
+ { id: "fund_waterfall", label: "Fund 2/20 waterfall", group: "Portfolio", formula: "carry over preferred hurdle",
77
+ params: [{ name: "committed", kind: "number", default: 100 }, { name: "invested", kind: "number", default: 90 }, { name: "distributed", kind: "number", default: 250 }],
78
+ run: (a) => { const r = Q.fundWaterfall(n(a.committed), n(a.invested), n(a.distributed)); return { grossMOIC: r.grossMOIC, netMOIC: r.netMOIC, dpi: r.dpi, gpCarry: r.gpCarry }; } },
79
+ { id: "power_law", label: "Power-law portfolio", group: "Portfolio", formula: "winners·mult + losers·(−1)",
80
+ params: [{ name: "companies", kind: "number", default: 30 }, { name: "winnerPct", kind: "number", default: 0.1 }, { name: "winnerMultiple", kind: "number", default: 20 }],
81
+ run: (a) => { const r = Q.powerLawPortfolio(n(a.companies, 30), n(a.winnerPct, 0.1), n(a.winnerMultiple, 20)); return { portfolioMOIC: r.totalPortfolioMOIC, winnerContributionPct: r.winnerContributionPct, lossRatio: r.lossRatio }; } },
82
+ { id: "hhi", label: "HHI concentration", group: "Portfolio", formula: "Σ share² × 10000",
83
+ params: [{ name: "shares", kind: "number[]", default: [0.4, 0.3, 0.2, 0.1] }],
84
+ run: (a) => { const r = Q.hhi(arr(a.shares)); return { hhi: r.hhi }; } },
85
+
86
+ // Signal / risk statistics
87
+ { id: "sharpe", label: "Sharpe ratio", group: "Statistics", formula: "mean(excess)/σ",
88
+ params: [{ name: "returns", kind: "number[]", default: [0.02, -0.01, 0.03, 0.015, -0.005] }, { name: "riskFree", kind: "number", default: 0 }],
89
+ run: (a) => ({ sharpe: Q.sharpeRatio(arr(a.returns), n(a.riskFree)) }) },
90
+ { id: "sortino", label: "Sortino ratio", group: "Statistics", formula: "mean(excess)/downsideDev",
91
+ params: [{ name: "returns", kind: "number[]", default: [0.02, -0.01, 0.03, 0.015, -0.005] }, { name: "riskFree", kind: "number", default: 0 }],
92
+ run: (a) => ({ sortino: Q.sortinoRatio(arr(a.returns), n(a.riskFree)) }) },
93
+ { id: "max_drawdown", label: "Max drawdown", group: "Statistics", formula: "max peak-to-trough decline",
94
+ params: [{ name: "equityCurve", kind: "number[]", default: [100, 110, 105, 120, 90, 130] }],
95
+ run: (a) => ({ maxDrawdown: Q.maxDrawdown(arr(a.equityCurve)) }) },
96
+ { id: "kelly", label: "Kelly criterion", group: "Statistics", formula: "(p·b − q)/b",
97
+ params: [{ name: "winProb", kind: "number", default: 0.55 }, { name: "winLossRatio", kind: "number", default: 1.8 }],
98
+ run: (a) => ({ kellyFraction: Q.kellyCriterion(n(a.winProb), n(a.winLossRatio)) }) },
99
+ { id: "zscore", label: "Z-score", group: "Statistics", formula: "(x − μ)/σ",
100
+ params: [{ name: "value", kind: "number", default: 211 }, { name: "mean", kind: "number", default: 180 }, { name: "std", kind: "number", default: 25 }],
101
+ run: (a) => ({ z: Q.zScore(n(a.value), n(a.mean), n(a.std)) }) },
102
+ { id: "effective_n", label: "Cluster Effective N (ICC Fix)", group: "Statistics", formula: "n / (1 + (m-1)·ρ)",
103
+ params: [{ name: "nominalN", kind: "number", default: 400 }, { name: "clusterSize", kind: "number", default: 20 }, { name: "icc", kind: "number", default: 0.05 }],
104
+ run: (a) => ({ effectiveN: Q.calcEffectiveN(n(a.nominalN), n(a.clusterSize), n(a.icc)) }) },
105
+ { id: "required_n", label: "Required Nominal N (Cluster)", group: "Statistics", formula: "nTarget · (1 + (m-1)·ρ)",
106
+ params: [{ name: "targetN", kind: "number", default: 100 }, { name: "clusterSize", kind: "number", default: 20 }, { name: "icc", kind: "number", default: 0.05 }],
107
+ run: (a) => ({ requiredNominalN: Q.calcRequiredNominalN(n(a.targetN), n(a.clusterSize), n(a.icc)) }) },
108
+ { id: "crct_power", label: "cRCT Power → Clusters Per Arm", group: "Statistics", formula: "two-arm cluster RCT sample size w/ ICC design effect + attrition",
109
+ params: [
110
+ { name: "delta", kind: "number", default: 0.5 }, { name: "sd", kind: "number", default: 1.5 },
111
+ { name: "alpha", kind: "number", default: 0.05 }, { name: "power", kind: "number", default: 0.80 },
112
+ { name: "icc", kind: "number", default: 0.02 }, { name: "clusterSize", kind: "number", default: 14 },
113
+ { name: "attrition", kind: "number", default: 0.20 },
114
+ ],
115
+ run: (a) => {
116
+ const r = Q.calcClusterRCTPower({ delta: n(a.delta, 0.5), sd: n(a.sd, 1.5), alpha: n(a.alpha, 0.05), power: n(a.power, 0.80), icc: n(a.icc, 0.02), clusterSize: n(a.clusterSize, 14), attrition: n(a.attrition, 0) });
117
+ return { individualsPerArm: r.individualsPerArm, designEffect: r.designEffect, evaluablePerArm: r.evaluablePerArm, clustersPerArmIdeal: r.clustersPerArmIdeal, recruitPerCluster: r.recruitPerCluster, clustersPerArmWithAttrition: r.clustersPerArmWithAttrition, totalClustersWithAttrition: r.totalClustersWithAttrition, totalRecruit: r.totalRecruit };
118
+ } },
119
+ { id: "attrition_check", label: "Attrition Adequacy Check", group: "Statistics", formula: "evaluable = recruited · (1−attrition) ≥ required?",
120
+ params: [
121
+ { name: "clustersPerArm", kind: "number", default: 15 }, { name: "recruitPerCluster", kind: "number", default: 14 },
122
+ { name: "attrition", kind: "number", default: 0.20 }, { name: "requiredEvaluablePerArm", kind: "number", default: 178 },
123
+ ],
124
+ run: (a) => {
125
+ const r = Q.calcAttritionAdequacy({ clustersPerArm: n(a.clustersPerArm, 15), recruitPerCluster: n(a.recruitPerCluster, 14), attrition: n(a.attrition, 0.20), requiredEvaluablePerArm: n(a.requiredEvaluablePerArm, 178) });
126
+ return { recruitedPerArm: r.recruitedPerArm, evaluablePerArm: r.evaluablePerArm, adequate: r.adequate ? 1 : 0, deficit: r.deficit };
127
+ } },
128
+ ];
129
+
130
+ const BY_ID = new Map(COMPUTE_REGISTRY.map((s) => [s.id, s]));
131
+
132
+ export interface ComputeCall {
133
+ id: string;
134
+ args: Record<string, number | number[]>;
135
+ }
136
+
137
+ export interface ComputeRecord {
138
+ id: string;
139
+ label: string;
140
+ group: string;
141
+ formula: string;
142
+ args: Record<string, number | number[]>;
143
+ result: Record<string, number> | null;
144
+ ok: boolean;
145
+ error?: string;
146
+ ms: number;
147
+ }
148
+
149
+ /** Execute a single whitelisted call. Never throws. */
150
+ export function runComputeCall(call: ComputeCall): ComputeRecord {
151
+ const spec = BY_ID.get(call.id);
152
+ const t0 = performance.now();
153
+ if (!spec) {
154
+ return { id: call.id, label: call.id, group: "?", formula: "", args: call.args, result: null, ok: false, error: `unknown function "${call.id}"`, ms: 0 };
155
+ }
156
+ try {
157
+ const raw = spec.run(call.args || {});
158
+ const obj = typeof raw === "number" ? { value: raw } : raw;
159
+ // Flag non-finite outputs rather than hiding them.
160
+ const cleaned: Record<string, number> = {};
161
+ let ok = true;
162
+ for (const [k, v] of Object.entries(obj)) {
163
+ cleaned[k] = v;
164
+ if (!isFinite(v)) ok = false;
165
+ }
166
+ return { id: spec.id, label: spec.label, group: spec.group, formula: spec.formula, args: call.args, result: cleaned, ok, error: ok ? undefined : "non-finite result (check inputs)", ms: performance.now() - t0 };
167
+ } catch (e) {
168
+ return { id: spec.id, label: spec.label, group: spec.group, formula: spec.formula, args: call.args, result: null, ok: false, error: (e as Error).message, ms: performance.now() - t0 };
169
+ }
170
+ }
171
+
172
+ /** Execute a batch of calls deterministically, in order. */
173
+ export function runComputeBatch(calls: ComputeCall[]): ComputeRecord[] {
174
+ return (calls || []).slice(0, 24).map(runComputeCall);
175
+ }
176
+
177
+ /** Schema fragment for the Logic Engine prompt: lists callable functions. */
178
+ export function registryPromptCatalog(): string {
179
+ const groups = new Map<string, ComputeSpec[]>();
180
+ for (const s of COMPUTE_REGISTRY) {
181
+ const g = groups.get(s.group) ?? [];
182
+ g.push(s);
183
+ groups.set(s.group, g);
184
+ }
185
+ const lines: string[] = [];
186
+ for (const [group, specs] of groups) {
187
+ lines.push(` ${group}:`);
188
+ for (const s of specs) {
189
+ const params = s.params.map((p) => `${p.name}:${p.kind}`).join(", ");
190
+ lines.push(` - ${s.id}(${params}) // ${s.formula}`);
191
+ }
192
+ }
193
+ return lines.join("\n");
194
+ }
195
+
196
+ /** Render finished compute records as a compact, model-readable fact block. */
197
+ export function computeFactsBlock(records: ComputeRecord[]): string {
198
+ if (!records.length) return "";
199
+ const lines = records.map((r) => {
200
+ if (!r.ok || !r.result) return ` • ${r.label}: COMPUTE FAILED (${r.error ?? "unknown"}) — do NOT cite a number for this.`;
201
+ const out = Object.entries(r.result).map(([k, v]) => `${k}=${fmt(v)}`).join(", ");
202
+ return ` • ${r.label} [${r.formula}] → ${out} (deterministic, verified)`;
203
+ });
204
+ return `VERIFIED COMPUTED VALUES (use these exact numbers; do not invent or alter them):\n${lines.join("\n")}`;
205
+ }
206
+
207
+ function fmt(v: number): string {
208
+ if (!isFinite(v)) return "NaN";
209
+ const a = Math.abs(v);
210
+ if (a !== 0 && a < 0.01) return v.toExponential(2);
211
+ if (a >= 1e9) return (v / 1e9).toFixed(2) + "B";
212
+ if (a >= 1e6) return (v / 1e6).toFixed(2) + "M";
213
+ if (a >= 1e3) return v.toLocaleString(undefined, { maximumFractionDigits: 1 });
214
+ return v.toFixed(Math.abs(v) < 10 ? 3 : 1);
215
+ }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Compute Worker — Isolated computation thread.
3
+ * Handles Pyodide execution, crypto operations, and heavy computation.
4
+ */
5
+
6
+ import { hestonCallPrice, sabrImpliedVol, doubleMachineLearning, calculateAdjustedPower } from "./advanced-math";
7
+ import { runSandbox } from "./py-sandbox";
8
+
9
+ let pyodideInstance: any = null;
10
+
11
+ self.onmessage = async (e: MessageEvent) => {
12
+ const { type, payload, id } = e.data;
13
+
14
+ try {
15
+ let result: any;
16
+
17
+ switch (type) {
18
+ case "compute":
19
+ result = await handleCompute(payload.fn, payload.args);
20
+ break;
21
+ case "pyodide":
22
+ result = await handlePyodide(payload.code, payload.timeout);
23
+ break;
24
+ case "crypto":
25
+ result = await handleCrypto(payload.operation, payload.data);
26
+ break;
27
+ case "scrape":
28
+ result = await handleScrape(payload.urls, payload.maxConcurrency);
29
+ break;
30
+ default:
31
+ throw new Error(`Unknown task type: ${type}`);
32
+ }
33
+
34
+ self.postMessage({ taskId: id, success: true, result });
35
+ } catch (error: any) {
36
+ self.postMessage({ taskId: id, success: false, error: error.message });
37
+ }
38
+ };
39
+
40
+ async function handleCompute(fn: string, args: any[]): Promise<any> {
41
+ switch (fn) {
42
+ case "heston":
43
+ return hestonCallPrice(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
44
+ case "sabr":
45
+ return sabrImpliedVol(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
46
+ case "dml":
47
+ return doubleMachineLearning(args[0], args[1], args[2]);
48
+ case "power":
49
+ return calculateAdjustedPower(args[0], args[1], args[2], args[3]);
50
+ case "sandbox":
51
+ return runSandbox(args[0]);
52
+ default:
53
+ throw new Error(`Unknown compute function: ${fn}`);
54
+ }
55
+ }
56
+
57
+ async function handlePyodide(code: string, timeout?: number): Promise<any> {
58
+ // Initialize Pyodide if not already loaded
59
+ if (!pyodideInstance) {
60
+ // @ts-ignore
61
+ const pyodide = await loadPyodide({
62
+ indexURL: "https://cdn.jsdelivr.net/pyodide/v0.25.0/full/",
63
+ });
64
+ pyodideInstance = pyodide;
65
+ }
66
+
67
+ // Execute with timeout protection
68
+ const timeoutPromise = new Promise((_, reject) =>
69
+ setTimeout(() => reject(new Error("Pyodide execution timeout")), timeout || 5000)
70
+ );
71
+
72
+ const execPromise = (async () => {
73
+ await pyodideInstance.loadPackagesFromImports(code);
74
+ return await pyodideInstance.runPythonAsync(code);
75
+ })();
76
+
77
+ return Promise.race([execPromise, timeoutPromise]);
78
+ }
79
+
80
+ async function handleCrypto(operation: string, data: string): Promise<any> {
81
+ switch (operation) {
82
+ case "hash": {
83
+ const encoder = new TextEncoder();
84
+ const dataBuffer = encoder.encode(data);
85
+ const hashBuffer = await crypto.subtle.digest("SHA-256", dataBuffer);
86
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
87
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
88
+ }
89
+ case "sign": {
90
+ // mTLS-like signing simulation
91
+ const encoder = new TextEncoder();
92
+ const dataBuffer = encoder.encode(data);
93
+ const key = await crypto.subtle.generateKey(
94
+ { name: "ECDSA", namedCurve: "P-256" },
95
+ true,
96
+ ["sign", "verify"]
97
+ );
98
+ const signature = await crypto.subtle.sign(
99
+ { name: "ECDSA", hash: "SHA-256" },
100
+ key.privateKey,
101
+ dataBuffer
102
+ );
103
+ return {
104
+ signature: Array.from(new Uint8Array(signature))
105
+ .map((b) => b.toString(16).padStart(2, "0"))
106
+ .join(""),
107
+ publicKey: await crypto.subtle.exportKey("jwk", key.publicKey),
108
+ };
109
+ }
110
+ default:
111
+ throw new Error(`Unknown crypto operation: ${operation}`);
112
+ }
113
+ }
114
+
115
+ async function handleScrape(urls: string[], maxConcurrency?: number): Promise<any[]> {
116
+ // Parallel scraping with concurrency limit
117
+ const results: any[] = [];
118
+ const queue = [...urls];
119
+ const active: Promise<void>[] = [];
120
+
121
+ while (queue.length > 0 || active.length > 0) {
122
+ while (active.length < (maxConcurrency || 4) && queue.length > 0) {
123
+ const url = queue.shift()!;
124
+ const promise = (async () => {
125
+ try {
126
+ const response = await fetch(url);
127
+ const text = await response.text();
128
+ results.push({ url, success: true, content: text });
129
+ } catch (error: any) {
130
+ results.push({ url, success: false, error: error.message });
131
+ }
132
+ })();
133
+ active.push(promise);
134
+ }
135
+
136
+ if (active.length > 0) {
137
+ await Promise.race(active);
138
+ const completedIndex = active.findIndex((p) => {
139
+ const idx = active.indexOf(p);
140
+ if (idx !== -1) {
141
+ active.splice(idx, 1);
142
+ return true;
143
+ }
144
+ return false;
145
+ });
146
+ if (completedIndex !== -1) {
147
+ active.splice(completedIndex, 1);
148
+ }
149
+ }
150
+ }
151
+
152
+ return results;
153
+ }
@@ -0,0 +1,120 @@
1
+ // Gemini + Gemma 4 connectors via Google AI Studio REST API (generativelanguage.googleapis.com)
2
+ // Docs: https://ai.google.dev/api/generate-content
3
+ // Both Gemini and open Gemma checkpoints are routed through the same v1beta endpoint.
4
+
5
+ export type GeminiModel =
6
+ | "gemini-3.5-flash"
7
+ | "gemini-3.1-flash-lite"
8
+ | "gemini-3-flash-preview"
9
+ | "gemini-2.5-pro"
10
+ | "gemini-2.5-flash"
11
+ | "gemini-2.5-flash-lite"
12
+ | "gemini-2.0-flash"
13
+ | "gemini-2.0-flash-lite"
14
+ | "gemma-3-27b-it"
15
+ | "gemma-3-12b-it"
16
+ | "gemma-3-4b-it"
17
+ | "gemma-3n-e4b-it"
18
+ | "gemma-4-26b-a4b-it"
19
+ | "gemma-4-31b-it";
20
+
21
+ export const GEMINI_MODELS: { id: GeminiModel; label: string; family: "gemini" | "gemma" }[] = [
22
+ { id: "gemini-3.5-flash", label: "Gemini 3.5 Flash", family: "gemini" },
23
+ { id: "gemini-3.1-flash-lite", label: "Gemini 3.1 Flash-Lite", family: "gemini" },
24
+ { id: "gemini-3-flash-preview", label: "Gemini 3 Flash Preview", family: "gemini" },
25
+ { id: "gemini-2.5-pro", label: "Gemini 2.5 Pro", family: "gemini" },
26
+ { id: "gemini-2.5-flash", label: "Gemini 2.5 Flash", family: "gemini" },
27
+ { id: "gemini-2.5-flash-lite", label: "Gemini 2.5 Flash-Lite", family: "gemini" },
28
+ { id: "gemini-2.0-flash", label: "Gemini 2.0 Flash", family: "gemini" },
29
+ { id: "gemini-2.0-flash-lite", label: "Gemini 2.0 Flash-Lite", family: "gemini" },
30
+ { id: "gemma-3-27b-it", label: "Gemma 3 27B (IT)", family: "gemma" },
31
+ { id: "gemma-3-12b-it", label: "Gemma 3 12B (IT)", family: "gemma" },
32
+ { id: "gemma-3-4b-it", label: "Gemma 3 4B (IT)", family: "gemma" },
33
+ { id: "gemma-3n-e4b-it", label: "Gemma 3n E4B (IT)", family: "gemma" },
34
+ { id: "gemma-4-26b-a4b-it", label: "Gemma 4 26B A4B (IT)", family: "gemma" },
35
+ { id: "gemma-4-31b-it", label: "Gemma 4 31B (IT)", family: "gemma" },
36
+ ];
37
+
38
+ export interface GenerateOptions {
39
+ model: GeminiModel;
40
+ apiKey: string;
41
+ maxOutputTokens?: number;
42
+ temperature?: number;
43
+ systemInstruction?: string;
44
+ signal?: AbortSignal;
45
+ }
46
+
47
+ export interface GenerateResult {
48
+ text: string;
49
+ promptTokens: number;
50
+ completionTokens: number;
51
+ totalTokens: number;
52
+ model: GeminiModel;
53
+ }
54
+
55
+ const BASE = "https://generativelanguage.googleapis.com/v1beta/models";
56
+
57
+ export async function geminiGenerate(prompt: string, opts: GenerateOptions): Promise<GenerateResult> {
58
+ const url = `${BASE}/${opts.model}:generateContent?key=${encodeURIComponent(opts.apiKey)}`;
59
+ const body: Record<string, unknown> = {
60
+ contents: [{ role: "user", parts: [{ text: prompt }] }],
61
+ generationConfig: {
62
+ temperature: opts.temperature ?? 0.2,
63
+ maxOutputTokens: opts.maxOutputTokens ?? 1024,
64
+ },
65
+ };
66
+ if (opts.systemInstruction) {
67
+ body.systemInstruction = { role: "system", parts: [{ text: opts.systemInstruction }] };
68
+ }
69
+
70
+ const res = await fetch(url, {
71
+ method: "POST",
72
+ headers: { "Content-Type": "application/json" },
73
+ body: JSON.stringify(body),
74
+ signal: opts.signal,
75
+ });
76
+
77
+ if (!res.ok) {
78
+ const detail = await res.text();
79
+ throw new Error(`Gemini API ${res.status}: ${detail.slice(0, 400)}`);
80
+ }
81
+ const data = (await res.json()) as {
82
+ candidates?: { content?: { parts?: { text?: string }[] } }[];
83
+ usageMetadata?: { promptTokenCount?: number; candidatesTokenCount?: number; totalTokenCount?: number };
84
+ };
85
+ const text =
86
+ data.candidates?.[0]?.content?.parts?.map((p) => p.text ?? "").join("") ?? "";
87
+ const u = data.usageMetadata ?? {};
88
+ return {
89
+ text,
90
+ promptTokens: u.promptTokenCount ?? 0,
91
+ completionTokens: u.candidatesTokenCount ?? 0,
92
+ totalTokens: u.totalTokenCount ?? 0,
93
+ model: opts.model,
94
+ };
95
+ }
96
+
97
+ // Convenience: generate strict JSON and parse it. Returns the parsed value or
98
+ // null if parsing fails (caller is responsible for fallback).
99
+ export async function geminiGenerateJSON<T = unknown>(
100
+ prompt: string,
101
+ opts: GenerateOptions,
102
+ ): Promise<{ value: T | null; raw: string; usage: GenerateResult }> {
103
+ const wrapped = prompt + "\n\nRespond with VALID JSON ONLY. No prose, no code fences.";
104
+ const usage = await geminiGenerate(wrapped, { ...opts, temperature: opts.temperature ?? 0.1 });
105
+ const cleaned = usage.text.replace(/```json\s*/gi, "").replace(/```/g, "").trim();
106
+ try {
107
+ return { value: JSON.parse(cleaned) as T, raw: usage.text, usage };
108
+ } catch {
109
+ // Try to extract first {...} or [...] block.
110
+ const m = cleaned.match(/[\[{][\s\S]*[\]}]/);
111
+ if (m) {
112
+ try {
113
+ return { value: JSON.parse(m[0]) as T, raw: usage.text, usage };
114
+ } catch {
115
+ /* fall through */
116
+ }
117
+ }
118
+ return { value: null, raw: usage.text, usage };
119
+ }
120
+ }