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.
- package/diagnostics.mjs +141 -0
- package/dist/compute.worker-j5ahIpF-.js +1 -0
- package/dist/graph.worker-DG6iGCB9.js +1 -0
- package/dist/index.html +2314 -0
- package/flatten-guide.md +248 -0
- package/index.html +12 -0
- package/package.json +38 -0
- package/src/App.orig.tsx +204 -0
- package/src/App.orig1.tsx +27 -0
- package/src/App.orig2.tsx +25 -0
- package/src/App.tsx +3 -0
- package/src/BaseApp.tsx +18 -0
- package/src/INTEGRATION_LEDGER.md +22 -0
- package/src/PERSIST_CANARY.orig.txt +1 -0
- package/src/PERSIST_CANARY.txt +1 -0
- package/src/REGRESSION_LEDGER.md +651 -0
- package/src/TEMPLATE_PIPELINE_AUDIT.md +208 -0
- package/src/WILLIAMS_PERSONA_GUIDE.md +62 -0
- package/src/chat/VeritasChat.tsx +69 -0
- package/src/chat/synthesis.ts +31 -0
- package/src/chat/tier.ts +45 -0
- package/src/components/AdaptersPage.orig.tsx +99 -0
- package/src/components/AdaptersPage.tsx +3 -0
- package/src/components/AdversarialPanel.tsx +136 -0
- package/src/components/AnchorBaselinePanel.tsx +75 -0
- package/src/components/AnswerPanel.tsx +60 -0
- package/src/components/ArtifactPanel.tsx +43 -0
- package/src/components/ChatApp.orig.tsx +1582 -0
- package/src/components/ChatApp.orig1.tsx +722 -0
- package/src/components/ChatApp.tsx +95 -0
- package/src/components/ChatAugmentPanels.tsx +73 -0
- package/src/components/CitationLedgerPanel.tsx +313 -0
- package/src/components/ComputeSandboxPanel.tsx +130 -0
- package/src/components/ConfigPanel.tsx +110 -0
- package/src/components/ControlPlanePage.tsx +195 -0
- package/src/components/CreativeTreeLifePage.tsx +234 -0
- package/src/components/CreativeTreeOfLifePanel.tsx +149 -0
- package/src/components/DebugTracePanel.tsx +137 -0
- package/src/components/DeepReasoningTrace.tsx +48 -0
- package/src/components/EntitySheetPanel.tsx +51 -0
- package/src/components/FailureModesPanel.tsx +104 -0
- package/src/components/GBSDashboard.tsx +239 -0
- package/src/components/GraphView.tsx +116 -0
- package/src/components/HUD.tsx +125 -0
- package/src/components/HypothesisPanel.tsx +67 -0
- package/src/components/InnovationGenomeEngine.tsx +792 -0
- package/src/components/InnovationPersonaGuide.tsx +348 -0
- package/src/components/InnovationPersonaPanel.tsx +289 -0
- package/src/components/LiveResourceHUD.tsx +109 -0
- package/src/components/LongWriterPanel.tsx +112 -0
- package/src/components/MainPipelineV10Bridge.tsx +72 -0
- package/src/components/MarkdownLite.tsx +63 -0
- package/src/components/MemoryInspector.tsx +38 -0
- package/src/components/MemoryMonitor.tsx +52 -0
- package/src/components/MemoryStressPanel.tsx +176 -0
- package/src/components/ModulesPage.tsx +171 -0
- package/src/components/PipelineDebugConsole.orig.tsx +1856 -0
- package/src/components/PipelineDebugConsole.tsx +3 -0
- package/src/components/PreFlightHUD.tsx +67 -0
- package/src/components/PrismaFetchTracePanel.tsx +87 -0
- package/src/components/ReportOSPanel.tsx +165 -0
- package/src/components/ResourceEstimatorPage.tsx +327 -0
- package/src/components/RichText.tsx +181 -0
- package/src/components/SagaOsPanel.tsx +605 -0
- package/src/components/SagaOsReference.tsx +421 -0
- package/src/components/SagaOsV2Panel.tsx +594 -0
- package/src/components/SagaStyleTab.tsx +382 -0
- package/src/components/SageBlueprintPanel.tsx +416 -0
- package/src/components/SharedChatInput.tsx +77 -0
- package/src/components/StatFinancePanel.tsx +190 -0
- package/src/components/StylePersonaPanel.tsx +128 -0
- package/src/components/TemplatesPage.tsx +300 -0
- package/src/components/TestPanel.tsx +63 -0
- package/src/components/TraceLog.tsx +89 -0
- package/src/components/V15CalibrationAugment.tsx +1134 -0
- package/src/components/V15CalibrationDialog.tsx +1871 -0
- package/src/components/V15Overlay.orig.tsx +120 -0
- package/src/components/V15Overlay.tsx +4 -0
- package/src/components/V15OverlayWrapper.tsx +362 -0
- package/src/components/V15Toggle.tsx +34 -0
- package/src/console/DiagnosticRecoveryPanel.tsx +358 -0
- package/src/console/EngineeringConsole.tsx +103 -0
- package/src/console/FictionSystemPanels.tsx +882 -0
- package/src/console/InspectorPanels.tsx +254 -0
- package/src/console/ManuscriptGraderPanel.tsx +182 -0
- package/src/console/RecursiveReviserPanel.tsx +245 -0
- package/src/console/SeedControlPanel.tsx +135 -0
- package/src/console/StoryControllerPanel.tsx +443 -0
- package/src/console/engineBridge.ts +258 -0
- package/src/console/gemini.ts +106 -0
- package/src/console/grading.ts +250 -0
- package/src/console/util.ts +45 -0
- package/src/fiction/continuity.ts +372 -0
- package/src/fiction/crash-protection.ts +111 -0
- package/src/fiction/diagnostics.ts +208 -0
- package/src/fiction/diff.ts +74 -0
- package/src/fiction/entity-state-machine.ts +214 -0
- package/src/fiction/nive-engine.ts +404 -0
- package/src/fiction/pipeline-selftest.ts +132 -0
- package/src/fiction/seed-control.ts +193 -0
- package/src/fiction/story-engine.ts +326 -0
- package/src/fiction/types.ts +68 -0
- package/src/flatten-guide.md +379 -0
- package/src/index.css +14 -0
- package/src/index.orig.css +13 -0
- package/src/lib/academic-sources.base.ts +188 -0
- package/src/lib/academic-sources.orig.ts +28 -0
- package/src/lib/academic-sources.ts +10 -0
- package/src/lib/advanced-math.ts +119 -0
- package/src/lib/adversarial-engine.base.ts +409 -0
- package/src/lib/adversarial-engine.ts +82 -0
- package/src/lib/ai-revision.ts +623 -0
- package/src/lib/app-state.tsx +426 -0
- package/src/lib/artifact-registry.ts +97 -0
- package/src/lib/artifacts.ts +180 -0
- package/src/lib/atlas-dr.ts +167 -0
- package/src/lib/browser-mtls.ts +127 -0
- package/src/lib/browser-queue.ts +221 -0
- package/src/lib/browser-search-scraper.base.ts +382 -0
- package/src/lib/browser-search-scraper.orig.ts +90 -0
- package/src/lib/browser-search-scraper.ts +10 -0
- package/src/lib/calc-interceptor.ts +82 -0
- package/src/lib/citation-lane-tap.ts +78 -0
- package/src/lib/citation-ledger-store.ts +369 -0
- package/src/lib/citation-ledger.ts +203 -0
- package/src/lib/compute-sandbox.ts +215 -0
- package/src/lib/compute.worker.ts +153 -0
- package/src/lib/connectors/gemini.ts +120 -0
- package/src/lib/connectors/jina.ts +233 -0
- package/src/lib/connectors/marketdata.ts +51 -0
- package/src/lib/connectors/prismafetch.base.ts +175 -0
- package/src/lib/connectors/prismafetch.ts +1 -0
- package/src/lib/connectors/serpapi.ts +65 -0
- package/src/lib/connectors/wikidata.ts +44 -0
- package/src/lib/constraints.ts +331 -0
- package/src/lib/continuation-detector.base.ts +153 -0
- package/src/lib/continuation-detector.ts +48 -0
- package/src/lib/contradraft.ts +168 -0
- package/src/lib/cors-proxy.ts +120 -0
- package/src/lib/coverage.ts +81 -0
- package/src/lib/debug/architecture-prescription.ts +556 -0
- package/src/lib/debug/covea-repair.ts +543 -0
- package/src/lib/debug/helios-ground.ts +319 -0
- package/src/lib/debug/intent-decomposer.ts +281 -0
- package/src/lib/debug/intent-lattice.ts +349 -0
- package/src/lib/debug/pipeline-diagnosis.ts +1149 -0
- package/src/lib/debug/pipeline-trace-bus.ts +424 -0
- package/src/lib/debug/prompt-forge.ts +678 -0
- package/src/lib/debug/repair-sites.ts +513 -0
- package/src/lib/debug/research-phase.ts +266 -0
- package/src/lib/debug/retrieval-context.ts +76 -0
- package/src/lib/debug/retrieval-hardener.ts +142 -0
- package/src/lib/debug/scraper-debug-runner.ts +576 -0
- package/src/lib/debug/scraper-forensics.ts +418 -0
- package/src/lib/debug/scraper-lane-roadmap.ts +136 -0
- package/src/lib/debug/self-test.ts +415 -0
- package/src/lib/debug/step-attribution.ts +211 -0
- package/src/lib/debug/template-rubric.ts +301 -0
- package/src/lib/debug/unified-innovation.ts +126 -0
- package/src/lib/debug/veritas-hybrid-scraper.ts +335 -0
- package/src/lib/defense-registry.ts +104 -0
- package/src/lib/defenses.ts +162 -0
- package/src/lib/deterministic-citation-ledger.ts +174 -0
- package/src/lib/elo-registry.base.ts +117 -0
- package/src/lib/elo-registry.ts +1 -0
- package/src/lib/entity-resolver.ts +291 -0
- package/src/lib/failure-modes.ts +267 -0
- package/src/lib/feature-registry.ts +69 -0
- package/src/lib/flaw-registry.ts +143 -0
- package/src/lib/flaws/_template.ts +52 -0
- package/src/lib/flaws/builtins.ts +63 -0
- package/src/lib/flaws/finance.ts +169 -0
- package/src/lib/flaws/fixers.ts +10 -0
- package/src/lib/flaws/index.ts +32 -0
- package/src/lib/flaws/legal.ts +157 -0
- package/src/lib/flaws/medical.ts +188 -0
- package/src/lib/flaws/original-defenses-pack.ts +81 -0
- package/src/lib/flaws/sample-declarative-pack.json +38 -0
- package/src/lib/flaws/selftest.ts +201 -0
- package/src/lib/flaws/software-extended.ts +125 -0
- package/src/lib/flaws/software-rn-webgl.ts +182 -0
- package/src/lib/flaws/statistics-advanced.ts +46 -0
- package/src/lib/flaws/statistics.ts +61 -0
- package/src/lib/gbse/config.ts +20 -0
- package/src/lib/gbse/engine.ts +226 -0
- package/src/lib/gbse/graph.ts +118 -0
- package/src/lib/gbse/graph.worker.ts +21 -0
- package/src/lib/gbse/tests.ts +117 -0
- package/src/lib/gbse/tiers.ts +65 -0
- package/src/lib/gbse/types.ts +94 -0
- package/src/lib/innovation-genome-engine-v2.orig.ts +1001 -0
- package/src/lib/innovation-genome-engine-v2.ts +3 -0
- package/src/lib/innovation-genome-engine.orig.ts +330 -0
- package/src/lib/innovation-genome-engine.ts +3 -0
- package/src/lib/innovation-genome-v10.orig.ts +314 -0
- package/src/lib/innovation-genome-v10.ts +2 -0
- package/src/lib/innovation-genome-v3.orig.ts +2015 -0
- package/src/lib/innovation-genome-v3.ts +2 -0
- package/src/lib/innovation-genome-v4.orig.ts +1959 -0
- package/src/lib/innovation-genome-v4.ts +2 -0
- package/src/lib/innovation-genome-v5.orig.ts +1210 -0
- package/src/lib/innovation-genome-v5.ts +2 -0
- package/src/lib/innovation-genome-v7.orig.ts +2549 -0
- package/src/lib/innovation-genome-v7.ts +2 -0
- package/src/lib/innovation-genome-v8.orig.ts +1485 -0
- package/src/lib/innovation-genome-v8.ts +2 -0
- package/src/lib/innovation-genome-v9.orig.ts +643 -0
- package/src/lib/innovation-genome-v9.ts +2 -0
- package/src/lib/jina.base.ts +293 -0
- package/src/lib/jina.ts +1 -0
- package/src/lib/live-telemetry.ts +61 -0
- package/src/lib/longwriter.ts +84 -0
- package/src/lib/manuscript-grade-v2.ts +298 -0
- package/src/lib/memory-governor.ts +173 -0
- package/src/lib/memory-stress-tests.ts +248 -0
- package/src/lib/model-intelligence.ts +48 -0
- package/src/lib/model-rotator.ts +75 -0
- package/src/lib/models.orig.ts +513 -0
- package/src/lib/models.ts +151 -0
- package/src/lib/n-deep.base.ts +592 -0
- package/src/lib/n-deep.ts +51 -0
- package/src/lib/nih-simulator.ts +56 -0
- package/src/lib/nih-vulnerability-fixes.ts +460 -0
- package/src/lib/omega-templates.base.ts +294 -0
- package/src/lib/omega-templates.ts +225 -0
- package/src/lib/omni-nexus.ts +64 -0
- package/src/lib/oracle-adapters.ts +67 -0
- package/src/lib/oracle-registry.ts +163 -0
- package/src/lib/orchestrator.ts +357 -0
- package/src/lib/output-boundary.ts +235 -0
- package/src/lib/overrides/vite-native-chaos-harness.ts +154 -0
- package/src/lib/overrides/vite-native-contract-plane.ts +245 -0
- package/src/lib/overrides/vite-native-doctor-plane.ts +208 -0
- package/src/lib/overrides/vite-native-knowledge-store.ts +267 -0
- package/src/lib/overrides/vite-native-policy-plane.ts +190 -0
- package/src/lib/overrides/vite-native-replay-plane.ts +197 -0
- package/src/lib/overrides/vite-native-runtime-plane.ts +106 -0
- package/src/lib/overrides/vite-native-scraper.ts +848 -0
- package/src/lib/overrides/vite-native-selftest-functional.ts +217 -0
- package/src/lib/overrides/vite-native-selftest.ts +183 -0
- package/src/lib/overrides/vite-native-snapshot-plane.ts +123 -0
- package/src/lib/philosophy-toolkit.ts +75 -0
- package/src/lib/pipeline.orig.ts +659 -0
- package/src/lib/pipeline.ts +42 -0
- package/src/lib/precache.ts +128 -0
- package/src/lib/py-sandbox.ts +205 -0
- package/src/lib/quality-score.ts +96 -0
- package/src/lib/quant-engine.ts +231 -0
- package/src/lib/quant-lib.ts +80 -0
- package/src/lib/reportos.ts +175 -0
- package/src/lib/research-os.ts +306 -0
- package/src/lib/resource-estimator.ts +114 -0
- package/src/lib/rpm-governor.ts +93 -0
- package/src/lib/runtime-estimator.ts +135 -0
- package/src/lib/sage/empty-space-v6.ts +560 -0
- package/src/lib/sage/empty-space-v7.ts +222 -0
- package/src/lib/sage/empty-space.ts +733 -0
- package/src/lib/sage/engine.ts +786 -0
- package/src/lib/sage/index.ts +17 -0
- package/src/lib/sage/judge.ts +246 -0
- package/src/lib/sage/prng.ts +53 -0
- package/src/lib/sage/reality-grounding.ts +380 -0
- package/src/lib/sage/repetition.ts +151 -0
- package/src/lib/sage/saga-os-v2-engines.ts +1870 -0
- package/src/lib/sage/saga-os-v2.ts +274 -0
- package/src/lib/sage/saga-os-v3-core.ts +1491 -0
- package/src/lib/sage/saga-os-v3-release.ts +739 -0
- package/src/lib/sage/saga-os-v4-aureate.ts +1161 -0
- package/src/lib/sage/saga-os-v4.ts +212 -0
- package/src/lib/sage/saga-os-v5.ts +205 -0
- package/src/lib/sage/saga-os-v6.ts +346 -0
- package/src/lib/sage/saga-os-v7.ts +314 -0
- package/src/lib/sage/saga-os-v8.ts +505 -0
- package/src/lib/sage/saga-os.ts +329 -0
- package/src/lib/sage/taxonomy.ts +403 -0
- package/src/lib/sage/unified-roll.ts +524 -0
- package/src/lib/sage/worked-sketches.ts +44 -0
- package/src/lib/sage.ts +166 -0
- package/src/lib/scraper-debug-bus.ts +53 -0
- package/src/lib/scraper-enhanced.orig.ts +153 -0
- package/src/lib/scraper-enhanced.ts +10 -0
- package/src/lib/scraper-hardener.base.orig.ts +155 -0
- package/src/lib/scraper-hardener.base.ts +317 -0
- package/src/lib/scraper-hardener.ts +1 -0
- package/src/lib/scraper-palisade/palisade-adjudicator.orig.ts +419 -0
- package/src/lib/scraper-palisade/palisade-adjudicator.ts +13 -0
- package/src/lib/scraper-vnext/arbiter-omega.orig.ts +688 -0
- package/src/lib/scraper-vnext/arbiter-omega.ts +13 -0
- package/src/lib/scraper-vnext/canonical-portfolio-augments.ts +479 -0
- package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.orig.ts +1529 -0
- package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.ts +13 -0
- package/src/lib/scraper-vnext/conclave-omega.ts +1830 -0
- package/src/lib/scraper-vnext/content-extractor-v2.ts +226 -0
- package/src/lib/scraper-vnext/diagnostics-suite.ts +36 -0
- package/src/lib/scraper-vnext/epistemic-packer.ts +97 -0
- package/src/lib/scraper-vnext/fusion-v2.ts +65 -0
- package/src/lib/scraper-vnext/hydra-reader.orig.ts +1216 -0
- package/src/lib/scraper-vnext/hydra-reader.ts +13 -0
- package/src/lib/scraper-vnext/native-scraper-browser-vnext.orig.ts +91 -0
- package/src/lib/scraper-vnext/native-scraper-browser-vnext.ts +13 -0
- package/src/lib/scraper-vnext/nexus-consensus.orig.ts +905 -0
- package/src/lib/scraper-vnext/nexus-consensus.ts +13 -0
- package/src/lib/scraper-vnext/portfolio-consensus-adjudicator.ts +804 -0
- package/src/lib/scraper-vnext/portfolio-consensus-memory.ts +377 -0
- package/src/lib/scraper-vnext/portfolio-terminal-governor.ts +548 -0
- package/src/lib/scraper-vnext/query-strategist.orig.ts +224 -0
- package/src/lib/scraper-vnext/query-strategist.ts +423 -0
- package/src/lib/scraper-vnext/retrieval-accelerator.ts +708 -0
- package/src/lib/scraper-vnext/retrieval-audit-augments.ts +477 -0
- package/src/lib/scraper-vnext/retrieval-control-plane.ts +904 -0
- package/src/lib/scraper-vnext/retrieval-policy-augments.ts +358 -0
- package/src/lib/scraper-vnext/safe-fetch-v2.ts +157 -0
- package/src/lib/scraper-vnext/sentinel-omega.ts +56 -0
- package/src/lib/scraper-vnext/sentinel-orchestrator.ts +69 -0
- package/src/lib/scraper-vnext/sibyl-oracle.orig.ts +413 -0
- package/src/lib/scraper-vnext/sibyl-oracle.ts +13 -0
- package/src/lib/scraper-vnext/smart-read-v2.ts +55 -0
- package/src/lib/scraper-vnext/spa-rescue-bridge.ts +608 -0
- package/src/lib/scraper-vnext/strata-engine.orig.ts +2666 -0
- package/src/lib/scraper-vnext/strata-engine.ts +13 -0
- package/src/lib/scraper-vnext/structured-source-adapter.orig.ts +369 -0
- package/src/lib/scraper-vnext/structured-source-adapter.ts +34 -0
- package/src/lib/scraper-vnext/terminal-complete.ts +224 -0
- package/src/lib/scraper-vnext/terminal-final.ts +277 -0
- package/src/lib/scraper-vnext/terminal-saturation.ts +345 -0
- package/src/lib/scraper-vnext/terminal-wire.ts +425 -0
- package/src/lib/scraper-vnext/vanguard-titanium.orig.ts +467 -0
- package/src/lib/scraper-vnext/vanguard-titanium.ts +17 -0
- package/src/lib/search-cache.ts +138 -0
- package/src/lib/sloop-runner.base.ts +223 -0
- package/src/lib/sloop-runner.ts +104 -0
- package/src/lib/sloop.ts +114 -0
- package/src/lib/small-model-adapters.ts +82 -0
- package/src/lib/sscp.ts +86 -0
- package/src/lib/system-map.ts +54 -0
- package/src/lib/uni-node.ts +86 -0
- package/src/lib/universal-rigor-guard.ts +433 -0
- package/src/lib/v15-gate-testbed.ts +274 -0
- package/src/lib/v15-gemini.base.ts +89 -0
- package/src/lib/v15-gemini.ts +1 -0
- package/src/lib/v15-grounding.orig.ts +241 -0
- package/src/lib/v15-grounding.ts +79 -0
- package/src/lib/v15-pipeline.base.ts +769 -0
- package/src/lib/v15-pipeline.orig.ts +1154 -0
- package/src/lib/v15-pipeline.ts +674 -0
- package/src/lib/v15-questions.ts +64 -0
- package/src/lib/v15-rate-limiter.orig.ts +91 -0
- package/src/lib/v15-rate-limiter.ts +48 -0
- package/src/lib/v15-state.base.ts +87 -0
- package/src/lib/v15-state.ts +28 -0
- package/src/lib/visual-table-generator.tsx +207 -0
- package/src/lib/wasm-runtime.ts +133 -0
- package/src/lib/williams-persona-guide.ts +265 -0
- package/src/lib/williams-style.base.ts +464 -0
- package/src/lib/williams-style.ts +59 -0
- package/src/lib/worker-pool.ts +96 -0
- package/src/lib/writing-tiers.ts +125 -0
- package/src/main.orig.tsx +10 -0
- package/src/main.tsx +10 -0
- package/src/utils/cn.orig.ts +6 -0
- package/src/utils/cn.ts +6 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +31 -0
- package/unify.mjs +537 -0
- 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
|
+
}
|