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,659 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 4-Stage Micro-Agent Pipeline (from research docs)
|
|
3
|
+
* ─────────────────────────────────────────────────
|
|
4
|
+
* Stage 1: Application-code pre-processing (temporal anchor, persona seed)
|
|
5
|
+
* Stage 2: Logic Engine Pass → structured JSON schema (Pydantic-style TS)
|
|
6
|
+
* Stage 3: Copywriter Pass → polished Markdown prose
|
|
7
|
+
* Stage 4: Application-code post-processing (sanitizer, citation cleaner)
|
|
8
|
+
*
|
|
9
|
+
* This is purely additive — the existing ChatApp still works without it.
|
|
10
|
+
* When enabled (deepResearch=true), the pipeline replaces the single-pass
|
|
11
|
+
* synthesis with a two-pass approach that resolves the 10/10 output issues.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { GenerateParams } from "./models";
|
|
15
|
+
import { generateSynthesizedResponse } from "./models";
|
|
16
|
+
import { extractConstraints, buildConstraintBlock, sanitizeOutput } from "./constraints";
|
|
17
|
+
import type { WilliamsPersona } from "./williams-style";
|
|
18
|
+
|
|
19
|
+
// ─── Stage 1 output (computed in code, injected into prompt) ────────────────
|
|
20
|
+
|
|
21
|
+
export interface TemporalAnchor {
|
|
22
|
+
currentDate: string; // ISO yyyy-mm-dd
|
|
23
|
+
currentDateHuman: string; // "May 29, 2026"
|
|
24
|
+
horizonEnd?: string; // ISO yyyy-mm-dd
|
|
25
|
+
horizonEndHuman?: string; // "July 28, 2026"
|
|
26
|
+
horizonDays?: number;
|
|
27
|
+
anchorStatement: string; // Injected verbatim into prompt
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function computeTemporalAnchor(userText: string): TemporalAnchor {
|
|
31
|
+
const now = new Date();
|
|
32
|
+
const iso = now.toISOString().slice(0, 10);
|
|
33
|
+
const human = now.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
|
|
34
|
+
|
|
35
|
+
const constraints = extractConstraints(userText);
|
|
36
|
+
let horizonEnd: string | undefined;
|
|
37
|
+
let horizonEndHuman: string | undefined;
|
|
38
|
+
let horizonDays: number | undefined;
|
|
39
|
+
|
|
40
|
+
if (constraints.timeHorizon?.days) {
|
|
41
|
+
const end = new Date(now.getTime() + constraints.timeHorizon.days * 86_400_000);
|
|
42
|
+
horizonEnd = end.toISOString().slice(0, 10);
|
|
43
|
+
horizonEndHuman = end.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
|
|
44
|
+
horizonDays = constraints.timeHorizon.days;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const anchorStatement = horizonEnd
|
|
48
|
+
? `TEMPORAL ANCHOR (injected by application code, not inferred by model):\n • Current date: ${human}\n • Target window end: ${horizonEndHuman} (${horizonDays} days from now)\n • Any event, catalyst, or data point occurring AFTER ${horizonEndHuman} is OUTSIDE the user's window and must be explicitly labeled as such.`
|
|
49
|
+
: `TEMPORAL ANCHOR (injected by application code):\n • Current date: ${human}`;
|
|
50
|
+
|
|
51
|
+
return { currentDate: iso, currentDateHuman: human, horizonEnd, horizonEndHuman, horizonDays, anchorStatement };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ─── Stage 2: Logic Engine Pass schema ──────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
export interface DataPointMatrix {
|
|
57
|
+
entityName: string;
|
|
58
|
+
metricValue: string;
|
|
59
|
+
isWithinTimeline: boolean;
|
|
60
|
+
immediateCatalysts: string[];
|
|
61
|
+
riskFactors: string[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface LogicEnginePayload {
|
|
65
|
+
queryIntentAnalysis: string;
|
|
66
|
+
temporalAnchorVerified: boolean;
|
|
67
|
+
dataMatrix: DataPointMatrix[];
|
|
68
|
+
sectorTrendSynthesis: string;
|
|
69
|
+
definitiveTacticalVerdict: string;
|
|
70
|
+
computeRequests?: { id: string; args: Record<string, number | number[]> }[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Scan for ALL balanced top-level {...} groups in a string. */
|
|
74
|
+
function balancedObjects(text: string): string[] {
|
|
75
|
+
const out: string[] = [];
|
|
76
|
+
let depth = 0, start = -1, inStr = false, esc = false;
|
|
77
|
+
for (let i = 0; i < text.length; i++) {
|
|
78
|
+
const ch = text[i];
|
|
79
|
+
if (inStr) {
|
|
80
|
+
if (esc) esc = false;
|
|
81
|
+
else if (ch === "\\") esc = true;
|
|
82
|
+
else if (ch === '"') inStr = false;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (ch === '"') { inStr = true; continue; }
|
|
86
|
+
if (ch === "{") { if (depth === 0) start = i; depth++; }
|
|
87
|
+
else if (ch === "}") { depth--; if (depth === 0 && start !== -1) { out.push(text.slice(start, i + 1)); start = -1; } }
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function repairJson(s: string): string {
|
|
93
|
+
return s
|
|
94
|
+
.replace(/[\u201C\u201D]/g, '"').replace(/[\u2018\u2019]/g, "'")
|
|
95
|
+
.replace(/,\s*([}\]])/g, "$1") // trailing commas
|
|
96
|
+
.replace(/}\s*{/g, "},{"); // missing commas between objects
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const EXPECTED_KEYS = ["query_intent_analysis", "queryIntentAnalysis", "definitive_tactical_verdict", "data_matrix"];
|
|
100
|
+
|
|
101
|
+
function extractStrictJson(raw: string): string {
|
|
102
|
+
// Prefer a fenced block if present
|
|
103
|
+
const fenced = raw.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
104
|
+
const source = fenced ? fenced[1] : raw;
|
|
105
|
+
const objs = balancedObjects(source).map(repairJson);
|
|
106
|
+
if (objs.length === 0) return repairJson(source.trim());
|
|
107
|
+
// Pick the object that contains the most expected keys (defends against
|
|
108
|
+
// stray { } inside the model's prose scratchpad).
|
|
109
|
+
let best = objs[0], bestScore = -1;
|
|
110
|
+
for (const o of objs) {
|
|
111
|
+
const score = EXPECTED_KEYS.reduce((acc, k) => acc + (o.includes(`"${k}"`) ? 1 : 0), 0);
|
|
112
|
+
if (score > bestScore) { bestScore = score; best = o; }
|
|
113
|
+
}
|
|
114
|
+
return best;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function tryParse(raw: string): unknown {
|
|
118
|
+
// 1. Best balanced object
|
|
119
|
+
try { return JSON.parse(extractStrictJson(raw)); } catch { /* */ }
|
|
120
|
+
// 2. Newline collapse
|
|
121
|
+
try { return JSON.parse(extractStrictJson(raw).replace(/\\?\n/g, " ")); } catch { /* */ }
|
|
122
|
+
// 3. Every balanced object, largest first
|
|
123
|
+
const objs = balancedObjects(raw).map(repairJson).sort((a, b) => b.length - a.length);
|
|
124
|
+
for (const o of objs) { try { return JSON.parse(o); } catch { /* */ } }
|
|
125
|
+
// 4. If all JSON parsing fails, we fall back to a stub object so the pipeline
|
|
126
|
+
// doesn't crash, allowing the Copywriter stage to use the raw text.
|
|
127
|
+
return {
|
|
128
|
+
queryIntentAnalysis: "JSON parsing failed. Recovering...",
|
|
129
|
+
temporalAnchorVerified: true,
|
|
130
|
+
dataMatrix: [{ entityName: "Fallback", metricValue: "N/A", isWithinTimeline: true, immediateCatalysts: [], riskFactors: [] }],
|
|
131
|
+
sectorTrendSynthesis: "Source extraction error, recovering from raw response: " + raw.slice(0, 500),
|
|
132
|
+
definitiveTacticalVerdict: "Attempting synthesis from unparsed data...",
|
|
133
|
+
computeRequests: []
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function parseLogicPayload(raw: string): LogicEnginePayload | null {
|
|
138
|
+
const json = tryParse(raw) as any;
|
|
139
|
+
if (!json) return null;
|
|
140
|
+
try {
|
|
141
|
+
// Normalise camelCase vs snake_case
|
|
142
|
+
return {
|
|
143
|
+
queryIntentAnalysis: json.query_intent_analysis ?? json.queryIntentAnalysis ?? "",
|
|
144
|
+
temporalAnchorVerified: json.temporal_anchor_verified ?? json.temporalAnchorVerified ?? false,
|
|
145
|
+
dataMatrix: (json.data_matrix ?? json.dataMatrix ?? []).map((d: Record<string, unknown>) => ({
|
|
146
|
+
entityName: d.entity_name ?? d.entityName ?? "",
|
|
147
|
+
metricValue: d.metric_value ?? d.metricValue ?? "",
|
|
148
|
+
isWithinTimeline: d.is_within_timeline ?? d.isWithinTimeline ?? false,
|
|
149
|
+
immediateCatalysts: d.immediate_catalysts ?? d.immediateCatalysts ?? [],
|
|
150
|
+
riskFactors: d.risk_factors ?? d.riskFactors ?? [],
|
|
151
|
+
})),
|
|
152
|
+
sectorTrendSynthesis: json.sector_trend_synthesis ?? json.sectorTrendSynthesis ?? "",
|
|
153
|
+
definitiveTacticalVerdict: json.definitive_tactical_verdict ?? json.definitiveTacticalVerdict ?? "",
|
|
154
|
+
computeRequests: Array.isArray(json.compute_requests ?? json.computeRequests)
|
|
155
|
+
? (json.compute_requests ?? json.computeRequests).map((c: Record<string, unknown>) => ({
|
|
156
|
+
id: String(c.id ?? c.fn ?? ""),
|
|
157
|
+
args: (c.args ?? c.arguments ?? {}) as Record<string, number | number[]>,
|
|
158
|
+
})).filter((c: { id: string }) => c.id)
|
|
159
|
+
: [],
|
|
160
|
+
} as LogicEnginePayload;
|
|
161
|
+
} catch {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ─── Stage 2 prompt ──────────────────────────────────────────────────────────
|
|
167
|
+
|
|
168
|
+
function buildLogicEnginePrompt(
|
|
169
|
+
userQuery: string,
|
|
170
|
+
anchor: TemporalAnchor,
|
|
171
|
+
retrievedData: { title: string; url: string; content: string }[],
|
|
172
|
+
constraintBlock: string,
|
|
173
|
+
catalog: string,
|
|
174
|
+
): string {
|
|
175
|
+
const sourceSummary = retrievedData
|
|
176
|
+
.slice(0, 12)
|
|
177
|
+
.map((s, i) => `[S${i + 1}] ${s.title}\n${s.content.slice(0, 600)}`)
|
|
178
|
+
.join("\n\n---\n\n");
|
|
179
|
+
|
|
180
|
+
return `Output a SINGLE raw JSON object. Start your response with { and end with }. No prose, no markdown fences, no commentary before or after. If a field is unknown, use an empty string or empty array — never omit a field.
|
|
181
|
+
|
|
182
|
+
${anchor.anchorStatement}
|
|
183
|
+
|
|
184
|
+
${constraintBlock}
|
|
185
|
+
|
|
186
|
+
SOURCES:
|
|
187
|
+
${sourceSummary}
|
|
188
|
+
|
|
189
|
+
USER QUERY: ${userQuery}
|
|
190
|
+
|
|
191
|
+
Return EXACTLY this shape (fill the values; keep all keys):
|
|
192
|
+
{
|
|
193
|
+
"query_intent_analysis": "",
|
|
194
|
+
"temporal_anchor_verified": true,
|
|
195
|
+
"data_matrix": [
|
|
196
|
+
{ "entity_name": "", "metric_value": "", "is_within_timeline": true, "immediate_catalysts": [], "risk_factors": [] }
|
|
197
|
+
],
|
|
198
|
+
"sector_trend_synthesis": "",
|
|
199
|
+
"definitive_tactical_verdict": "",
|
|
200
|
+
"compute_requests": []
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
DETERMINISTIC COMPUTE: If — and ONLY if — the question genuinely needs a numeric calculation that can be derived from numbers PRESENT IN THE SOURCES, add entries to "compute_requests". Each is { "id": "<function>", "args": { ... } }. Use the fewest calls necessary. Never request a calc if the required inputs are not in the sources. Available functions:
|
|
204
|
+
${catalog}
|
|
205
|
+
|
|
206
|
+
Rules: catalysts in "immediate_catalysts" must fall INSIDE the ${anchor.horizonDays ?? 90}-day window; if a catalyst is outside, put it in "risk_factors" and set "is_within_timeline" false. Keep every string under 200 characters. Do not include trailing commas.`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ─── Stage 3 prompt ──────────────────────────────────────────────────────────
|
|
210
|
+
|
|
211
|
+
function buildCopywriterPrompt(payload: LogicEnginePayload, persona: WilliamsPersona, query: string): string {
|
|
212
|
+
return `You are an elite analyst writing the FINAL reader-facing brief. The reader sees ONLY what you place between the answer tags.
|
|
213
|
+
|
|
214
|
+
STYLE (apply invisibly; NEVER name a style, persona, lesson, or framework):
|
|
215
|
+
${persona.archetype.name} — ${persona.archetype.desc}
|
|
216
|
+
|
|
217
|
+
DATA TO COMMUNICATE:
|
|
218
|
+
${JSON.stringify(payload, null, 2)}
|
|
219
|
+
|
|
220
|
+
USER ASKED: ${query}
|
|
221
|
+
|
|
222
|
+
ABSOLUTE RULES:
|
|
223
|
+
- Do NOT show any planning, thinking, self-correction, outlines, bullet plans, "Self-correction:", "Body Section", "Introduction:", "Verdict:" labels, or numbered drafting steps.
|
|
224
|
+
- Do NOT restate these rules. Do NOT mention "payload", "JSON", "data matrix", "sources", or "persona".
|
|
225
|
+
- Write ONLY the finished prose a client would read.
|
|
226
|
+
- Do NOT collapse into "the provided data does not contain" or "insufficient evidence" if DATA TO COMMUNICATE contains any usable synthesis, entities, trend, verdict, or source-derived facts. Instead produce the best evidence-bounded answer and explicitly name only the narrow missing fields.
|
|
227
|
+
- Open with the verdict in one sentence. Use a Markdown table only if there are 2+ entities.
|
|
228
|
+
- Flag any catalyst with is_within_timeline=false using "⚠️ Outside window".
|
|
229
|
+
- End with one decisive bottom-line sentence.
|
|
230
|
+
- NEVER leave bracketed placeholders ([list of...], [description of...], [insert...], [TBD]). Fill every slot with real, specific content or omit the slot entirely.
|
|
231
|
+
- If you use the heading "SABV", it MUST contain a genuine Sex-as-a-Biological-Variable plan (sex stratification / disaggregation). NEVER label statistical nesting, clustering, or GLMM content as SABV — that belongs under "Statistical Analysis".
|
|
232
|
+
- In a grant, hypothetical/projected outcomes go under "Expected Outcomes / Impact", never under a "Results" heading.
|
|
233
|
+
- NEVER emit raw XML/HTML tags like <paragraph>, <section>, <div>, <p> in your output. Use only clean Markdown (headings, bold, lists, tables).
|
|
234
|
+
- NEVER say "the provided data does not contain" or "I am unable to propose" or "I cannot predict" when the DATA TO COMMUNICATE section contains usable content. PRODUCE an answer from whatever data is available.
|
|
235
|
+
- If an OMEGA template (NIH-GRANT-SRF, OMEGA-SCIENCE, etc.) is active, your output MUST follow that template's section structure exactly. Do not regress to generic paragraphs.
|
|
236
|
+
- NUMERICAL DETERMINISM: You MUST NOT guess or estimate sample sizes, power (beta), statistical effects, or budgets. If a study design needs these, add compute_requests entries to calculate them deterministically.
|
|
237
|
+
|
|
238
|
+
Wrap the ENTIRE finished answer between these exact tags and write nothing outside them:
|
|
239
|
+
<final_answer>
|
|
240
|
+
...your finished brief here...
|
|
241
|
+
</final_answer>`;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** Extract the content between <final_answer> tags; fall back to whole text.
|
|
245
|
+
* TRUNCATION GUARD: if the extracted fragment is suspiciously short relative
|
|
246
|
+
* to the raw response, the model was likely truncated mid-generation and the
|
|
247
|
+
* tag captured only the tail. In that case, use the full raw response. */
|
|
248
|
+
function extractFinalAnswer(raw: string): string {
|
|
249
|
+
const m = raw.match(/<final_answer>([\s\S]*?)<\/final_answer>/i);
|
|
250
|
+
if (m) {
|
|
251
|
+
const extracted = m[1].trim();
|
|
252
|
+
// If the extracted content is less than 40% of the raw, the model probably
|
|
253
|
+
// truncated mid-generation and the tag only captured the tail fragment.
|
|
254
|
+
if (extracted.length < raw.length * 0.4 && raw.length > 500) {
|
|
255
|
+
return raw.replace(/<\/?final_answer>/gi, "").trim();
|
|
256
|
+
}
|
|
257
|
+
return extracted;
|
|
258
|
+
}
|
|
259
|
+
// Tag opened but not closed (truncation) — take everything after the open tag.
|
|
260
|
+
const open = raw.match(/<final_answer>([\s\S]*)$/i);
|
|
261
|
+
if (open) {
|
|
262
|
+
const extracted = open[1].trim();
|
|
263
|
+
if (extracted.length < raw.length * 0.4 && raw.length > 500) {
|
|
264
|
+
return raw.replace(/<\/?final_answer>/gi, "").trim();
|
|
265
|
+
}
|
|
266
|
+
return extracted;
|
|
267
|
+
}
|
|
268
|
+
return raw;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
import { cleanOutput as cleanOutputBoundary } from "./output-boundary";
|
|
272
|
+
import { runNDeep, type NDeepPassRecord } from "./n-deep";
|
|
273
|
+
import { runAdversarialRedTeam, buildRepairBlock } from "./adversarial-engine";
|
|
274
|
+
import { throttle } from "./rpm-governor";
|
|
275
|
+
import { registryPromptCatalog, runComputeBatch, computeFactsBlock, type ComputeRecord } from "./compute-sandbox";
|
|
276
|
+
import { resolveEntities, type EntitySheet } from "./entity-resolver";
|
|
277
|
+
import { buildArtifactPromptBlock, resolveArtifactRequest, shouldResolveArtifacts, type ArtifactResponse } from "./artifacts";
|
|
278
|
+
|
|
279
|
+
// ─── Stage 4 post-processing ─────────────────────────────────────────────────
|
|
280
|
+
|
|
281
|
+
function stage4Clean(raw: string): string {
|
|
282
|
+
// First pass: deterministic boundary detector (handles the leak pattern where
|
|
283
|
+
// the model dumps Current Date / Style Persona / Note: Since I am an AI / §0
|
|
284
|
+
// / Refining Suggestions / First sentence blocks BEFORE the real answer).
|
|
285
|
+
const boundary = cleanOutputBoundary(raw);
|
|
286
|
+
return _legacyStage4Clean(boundary.cleaned);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function _legacyStage4Clean(raw: string): string {
|
|
290
|
+
const original = raw;
|
|
291
|
+
// Remove raw [Source N] / [Source N, M] / [Source N, M, P] citations
|
|
292
|
+
let s = raw.replace(/\[Source\s*\d+(?:\s*,\s*(?:Source\s*)?\d+)*\s*\]/gi, "");
|
|
293
|
+
|
|
294
|
+
// Strip leaked scratchpad ONLY when a clear marker exists AND there is
|
|
295
|
+
// substantial prose after it. We never keep-after-last-marker blindly,
|
|
296
|
+
// because that destroyed legitimate multi-section content (the "Omitted as
|
|
297
|
+
// per instructions" + single-sentence regression). Instead we drop the
|
|
298
|
+
// marker LINE itself and let the bullet filter handle the rest.
|
|
299
|
+
const scratchLine = /^\s*[*>-]?\s*(Self-correction:|Body Section|Applying [^\n]*framework|Final Polish|Check "Climactic ordering"|Scratchpad:|Thinking:|Plan:)/i;
|
|
300
|
+
s = s.split("\n").filter((line) => !scratchLine.test(line)).join("\n");
|
|
301
|
+
|
|
302
|
+
// Drop lines that are pure CoT bullets (e.g. " * Strong verbs (L3).")
|
|
303
|
+
// Tightened so it only matches the leaked style-lesson bullets, never real
|
|
304
|
+
// content bullets that merely start with a flagged word.
|
|
305
|
+
const cotLine = /^\s*[*•-]\s*(Strong verbs|Characters as subjects|Varied sentence|Repeat key|Cumulative sentences|Climactic ordering|Reasonable concision|Minimize metadiscourse|Subordination|Strategic passive|Clear global)\b[^\n]{0,40}\(L\d/i;
|
|
306
|
+
s = s.split("\n").filter(line => !cotLine.test(line)).join("\n");
|
|
307
|
+
|
|
308
|
+
// Strip the Williams lesson tags like "(L3)", "(L5)", "(L3/L4)" if they leaked
|
|
309
|
+
s = s.replace(/\((?:L\d+(?:\/L\d+)?(?:,\s*)?)+\)/g, "");
|
|
310
|
+
|
|
311
|
+
// Strip leaked persona/style header lines that sometimes precede the answer
|
|
312
|
+
s = s.replace(/^\s*"?The [A-Z][a-z]+"?\s*\([^)]*\)\.?\s*$/gm, "");
|
|
313
|
+
s = s.replace(/^\s*Elite financial communicator[^\n]*$/gim, "");
|
|
314
|
+
|
|
315
|
+
// Strip meta-discourse phrases
|
|
316
|
+
const metaPhrases = [
|
|
317
|
+
/based on the (?:provided )?(?:data|search results?|payload|json)/gi,
|
|
318
|
+
/according to the (?:search|retriev|payload)/gi,
|
|
319
|
+
/the (?:retrieved?|source) (?:data |documents? )?(?:shows?|indicates?|states?)/gi,
|
|
320
|
+
/as (?:an?|the) AI[,.]?/gi,
|
|
321
|
+
/in conclusion[,.]?/gi,
|
|
322
|
+
];
|
|
323
|
+
for (const re of metaPhrases) s = s.replace(re, "");
|
|
324
|
+
|
|
325
|
+
const cleaned = s.replace(/\n{3,}/g, "\n\n").trim();
|
|
326
|
+
|
|
327
|
+
// SAFETY FLOOR: if aggressive cleaning collapsed the answer to a stub while
|
|
328
|
+
// the original had real substance, the cleaner mis-fired — return the
|
|
329
|
+
// original (minus raw citations) rather than emitting a stripped husk.
|
|
330
|
+
const originalBody = original.replace(/\[Source\s*\d+\]/gi, "").trim();
|
|
331
|
+
if (originalBody.length > 400 && cleaned.length < Math.max(200, originalBody.length * 0.35)) {
|
|
332
|
+
return originalBody.replace(/\n{3,}/g, "\n\n").trim();
|
|
333
|
+
}
|
|
334
|
+
return cleaned;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ─── Main pipeline entry point ───────────────────────────────────────────────
|
|
338
|
+
|
|
339
|
+
export interface PipelineTrace {
|
|
340
|
+
stage: number;
|
|
341
|
+
label: string;
|
|
342
|
+
ts: number;
|
|
343
|
+
data?: unknown;
|
|
344
|
+
ok: boolean;
|
|
345
|
+
detail?: string;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export interface PipelineResult {
|
|
349
|
+
finalText: string;
|
|
350
|
+
logicPayload: LogicEnginePayload | null;
|
|
351
|
+
anchor: TemporalAnchor;
|
|
352
|
+
trace: PipelineTrace[];
|
|
353
|
+
sanitizerRemovedSegments: number;
|
|
354
|
+
usedMultiPass: boolean;
|
|
355
|
+
computeRecords: ComputeRecord[];
|
|
356
|
+
entitySheet: EntitySheet | null;
|
|
357
|
+
artifactResponse: ArtifactResponse | null;
|
|
358
|
+
adversarialPasses?: import("./n-deep").NDeepPassRecord[];
|
|
359
|
+
adversarialStable?: boolean;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export async function runMultiPassPipeline(opts: {
|
|
363
|
+
userQuery: string;
|
|
364
|
+
retrievedData: { title: string; url: string; content: string }[];
|
|
365
|
+
baseParams: GenerateParams;
|
|
366
|
+
persona: WilliamsPersona;
|
|
367
|
+
templateBlock?: string;
|
|
368
|
+
artifactBlock?: string;
|
|
369
|
+
memory?: Record<string, any>;
|
|
370
|
+
/** Enable N-Deep recursive adversarial refinement (power-user toggle). */
|
|
371
|
+
nDeep?: boolean;
|
|
372
|
+
nDeepMaxPasses?: number;
|
|
373
|
+
/** Active template archetype id, used to select structural gates. */
|
|
374
|
+
templateId?: string;
|
|
375
|
+
/** Model RPM ceiling for throttling adversarial/repair calls. */
|
|
376
|
+
rpm?: number;
|
|
377
|
+
onTrace?: (t: PipelineTrace) => void;
|
|
378
|
+
}): Promise<PipelineResult> {
|
|
379
|
+
const trace: PipelineTrace[] = [];
|
|
380
|
+
const push = (t: PipelineTrace) => {
|
|
381
|
+
// OOM FIX: never retain large data payloads in the trace. Stringify+cap to
|
|
382
|
+
// 240 chars at the source so the trace array can't hold full logicPayload,
|
|
383
|
+
// computeRecords, or defect arrays alive in React state.
|
|
384
|
+
const slim: PipelineTrace = t.data !== undefined
|
|
385
|
+
? { ...t, data: (() => { try { return JSON.stringify(t.data).slice(0, 240); } catch { return String(t.data).slice(0, 240); } })() }
|
|
386
|
+
: t;
|
|
387
|
+
if (trace.length < 60) trace.push(slim); // hard cap trace length
|
|
388
|
+
opts.onTrace?.(slim);
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
// ── Stage 1 ──────────────────────────────────────────────────────────────
|
|
392
|
+
const anchor = computeTemporalAnchor(opts.userQuery);
|
|
393
|
+
const constraints = extractConstraints(opts.userQuery);
|
|
394
|
+
const constraintBlock = buildConstraintBlock(constraints);
|
|
395
|
+
push({ stage: 1, label: "Temporal anchor computed", ts: Date.now(), ok: true, data: anchor });
|
|
396
|
+
|
|
397
|
+
// ── Stage 1.5: Deterministic Entity Resolution ─────────────────────────
|
|
398
|
+
// Extracts tickers, company names, prices, and metrics from RETRIEVED
|
|
399
|
+
// source text only. The model never invents a company name or number.
|
|
400
|
+
const entitySheet = resolveEntities(opts.retrievedData, opts.userQuery);
|
|
401
|
+
push({
|
|
402
|
+
stage: 1.5,
|
|
403
|
+
label: `Entity resolver: ${entitySheet.entities.length} verified entities, ${entitySheet.weakEntities.length} weak`,
|
|
404
|
+
ts: Date.now(),
|
|
405
|
+
ok: entitySheet.entities.length > 0,
|
|
406
|
+
data: entitySheet.entities.map((e) => `${e.ticker} (${e.name}): ${Object.keys(e.facts).length} facts, ${e.sourceCount} sources`),
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// ── Stage 1.6: Deterministic Artifact Resolution ───────────────────────
|
|
410
|
+
// Equity/market prompts get a backend-resolved artifact sheet before any
|
|
411
|
+
// model synthesis. Tickers/names come from the artifact registry; prices and
|
|
412
|
+
// earnings appear only when a live resolver is configured.
|
|
413
|
+
let artifactResponse: ArtifactResponse | null = null;
|
|
414
|
+
if (shouldResolveArtifacts(opts.userQuery)) {
|
|
415
|
+
const tickers = Array.from(new Set([
|
|
416
|
+
...constraints.namedEntities,
|
|
417
|
+
...entitySheet.entities.map((e) => e.ticker),
|
|
418
|
+
])).slice(0, 12);
|
|
419
|
+
artifactResponse = await resolveArtifactRequest({
|
|
420
|
+
type: "earnings",
|
|
421
|
+
tickers,
|
|
422
|
+
windowStart: anchor.currentDate,
|
|
423
|
+
windowEnd: anchor.horizonEnd,
|
|
424
|
+
});
|
|
425
|
+
push({
|
|
426
|
+
stage: 1.6,
|
|
427
|
+
label: `Artifact resolver: ${artifactResponse.resolved.length} resolved, ${artifactResponse.unresolved.length} unresolved`,
|
|
428
|
+
ts: Date.now(),
|
|
429
|
+
ok: artifactResponse.resolved.length > 0,
|
|
430
|
+
data: artifactResponse.resolved.map((a) => `${a.ticker} (${a.name}) live=${a.hasLiveData}`),
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// ── Stage 2: Logic Engine Pass ───────────────────────────────────────────
|
|
435
|
+
push({ stage: 2, label: "Logic Engine Pass — requesting structured JSON", ts: Date.now(), ok: true });
|
|
436
|
+
const artifactBlock = artifactResponse ? buildArtifactPromptBlock(artifactResponse) : "";
|
|
437
|
+
|
|
438
|
+
// ADVERSARIAL PRE-DRAFT (Module ContraDraft §181-§186)
|
|
439
|
+
const adversarialPrompt = `ADVERSARIAL RED-TEAM TASK:
|
|
440
|
+
1. Construct a Naive Baseline (obvious high-prob answer).
|
|
441
|
+
2. Generate 2 ContraDraft Alternatives (fail under stress).
|
|
442
|
+
3. Run a Tournament to verify the Optimal Path.
|
|
443
|
+
4. Set a Falsification Gate (H_neg + Boundary Conditions).
|
|
444
|
+
Do this internally and use the results to harden the logic.`;
|
|
445
|
+
|
|
446
|
+
// UNIFIED MEMORY INTEGRATION: Inject prior findings into the logic engine context
|
|
447
|
+
const memoryBlock = Object.keys(opts.memory || {}).length > 0
|
|
448
|
+
? `\n\nUNIFIED MEMORY (prior findings from session):\n${JSON.stringify(opts.memory)}`
|
|
449
|
+
: "";
|
|
450
|
+
|
|
451
|
+
const logicPrompt = buildLogicEnginePrompt(
|
|
452
|
+
opts.userQuery,
|
|
453
|
+
anchor,
|
|
454
|
+
opts.retrievedData,
|
|
455
|
+
constraintBlock + "\n\n" + adversarialPrompt + "\n\n" + entitySheet.promptBlock + (artifactBlock ? "\n\n" + artifactBlock : "") + memoryBlock,
|
|
456
|
+
registryPromptCatalog()
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
let logicPayload: LogicEnginePayload | null = null;
|
|
460
|
+
try {
|
|
461
|
+
const rawLogic = await generateSynthesizedResponse({
|
|
462
|
+
...opts.baseParams,
|
|
463
|
+
userMessage: logicPrompt,
|
|
464
|
+
retrievedWebData: undefined,
|
|
465
|
+
conversationHistory: [],
|
|
466
|
+
});
|
|
467
|
+
logicPayload = parseLogicPayload(rawLogic);
|
|
468
|
+
// One stricter retry if the first attempt did not yield parseable JSON.
|
|
469
|
+
if (!logicPayload) {
|
|
470
|
+
push({ stage: 2, label: "Logic payload not parseable — retrying with one-shot repair", ts: Date.now(), ok: false });
|
|
471
|
+
const repairPrompt = `YOUR PREVIOUS REPLY WAS NOT VALID JSON. Extract the structured facts into ONLY the JSON object below. Do NOT write prose.
|
|
472
|
+
Required JSON schema:
|
|
473
|
+
{
|
|
474
|
+
"query_intent_analysis": "",
|
|
475
|
+
"temporal_anchor_verified": true,
|
|
476
|
+
"data_matrix": [
|
|
477
|
+
{ "entity_name": "", "metric_value": "", "is_within_timeline": true, "immediate_catalysts": [], "risk_factors": [] }
|
|
478
|
+
],
|
|
479
|
+
"sector_trend_synthesis": "",
|
|
480
|
+
"definitive_tactical_verdict": ""
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
INVALID REPLY:
|
|
484
|
+
${rawLogic.slice(0, 1000)}`;
|
|
485
|
+
|
|
486
|
+
const retryRaw = await generateSynthesizedResponse({
|
|
487
|
+
...opts.baseParams, userMessage: repairPrompt, retrievedWebData: undefined, conversationHistory: [],
|
|
488
|
+
});
|
|
489
|
+
logicPayload = parseLogicPayload(retryRaw);
|
|
490
|
+
}
|
|
491
|
+
push({ stage: 2, label: logicPayload ? "Logic payload validated ✓" : "Logic payload parse failed — falling back to single-pass", ts: Date.now(), ok: !!logicPayload, data: logicPayload });
|
|
492
|
+
} catch (err) {
|
|
493
|
+
push({ stage: 2, label: `Logic Engine error: ${(err as Error).message}`, ts: Date.now(), ok: false });
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// ── Stage 2.5: Deterministic Compute Sandbox ─────────────────────────────
|
|
497
|
+
let computeRecords: ComputeRecord[] = [];
|
|
498
|
+
let computeFacts = "";
|
|
499
|
+
if (logicPayload?.computeRequests && logicPayload.computeRequests.length > 0) {
|
|
500
|
+
computeRecords = runComputeBatch(logicPayload.computeRequests);
|
|
501
|
+
computeFacts = computeFactsBlock(computeRecords);
|
|
502
|
+
const okCount = computeRecords.filter((r) => r.ok).length;
|
|
503
|
+
push({ stage: 2.5, label: `Compute sandbox: ${okCount}/${computeRecords.length} deterministic calc(s) verified`, ts: Date.now(), ok: okCount === computeRecords.length, data: computeRecords });
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// ── Build compact source evidence block for the Copywriter ───────────────
|
|
507
|
+
// This is THE FIX for the "headers without bodies" / stub output regression.
|
|
508
|
+
// Previous versions sent `retrievedWebData: undefined` to Stage 3, leaving
|
|
509
|
+
// the model with only the Logic Engine JSON payload and no actual source text.
|
|
510
|
+
// Now we inject 16 capped sources directly into the copywriter prompt AND pass
|
|
511
|
+
// them via retrievedWebData so the model has two exposure paths to evidence.
|
|
512
|
+
const copywriterSources = opts.retrievedData.slice(0, 16).map(s => ({
|
|
513
|
+
title: s.title, url: s.url, content: (s.content || "").slice(0, 800),
|
|
514
|
+
}));
|
|
515
|
+
const sourceEvidenceBlock = copywriterSources.length > 0
|
|
516
|
+
? `\n\nSOURCE EVIDENCE (ground your prose in these — do NOT say "the data does not contain"):\n${copywriterSources.map((s, i) => `[S${i + 1}] ${s.title}\n${s.content.slice(0, 600)}`).join("\n---\n")}`
|
|
517
|
+
: "";
|
|
518
|
+
|
|
519
|
+
// ── Stage 3: Copywriter Pass ─────────────────────────────────────────────
|
|
520
|
+
let finalText = "";
|
|
521
|
+
if (logicPayload) {
|
|
522
|
+
push({ stage: 3, label: "Copywriter Pass — translating payload + source evidence to prose", ts: Date.now(), ok: true });
|
|
523
|
+
const copyPrompt = buildCopywriterPrompt(logicPayload, opts.persona, opts.userQuery)
|
|
524
|
+
+ sourceEvidenceBlock
|
|
525
|
+
+ `\n\n${entitySheet.promptBlock}`
|
|
526
|
+
+ (artifactBlock ? `\n\n${artifactBlock}` : "")
|
|
527
|
+
+ (computeFacts ? `\n\n${computeFacts}` : "")
|
|
528
|
+
+ (opts.templateBlock ? `\n\n${opts.templateBlock}` : "");
|
|
529
|
+
try {
|
|
530
|
+
const rawCopy = await generateSynthesizedResponse({
|
|
531
|
+
...opts.baseParams,
|
|
532
|
+
userMessage: copyPrompt,
|
|
533
|
+
// KEY FIX: pass source evidence to the model's data context window
|
|
534
|
+
retrievedWebData: copywriterSources,
|
|
535
|
+
conversationHistory: [],
|
|
536
|
+
});
|
|
537
|
+
finalText = extractFinalAnswer(rawCopy);
|
|
538
|
+
// Detect empty extraction
|
|
539
|
+
if (!finalText || finalText.trim().length < 100) {
|
|
540
|
+
push({ stage: 3, label: "Copywriter extraction too short — using raw response", ts: Date.now(), ok: false });
|
|
541
|
+
finalText = rawCopy;
|
|
542
|
+
}
|
|
543
|
+
push({ stage: 3, label: `Copywriter Pass complete: ${finalText.length} chars`, ts: Date.now(), ok: true });
|
|
544
|
+
} catch (err) {
|
|
545
|
+
push({ stage: 3, label: `Copywriter error: ${(err as Error).message} — falling back`, ts: Date.now(), ok: false });
|
|
546
|
+
logicPayload = null; // force fallback below
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// ── Fallback: single-pass synthesis ─────────────────────────────────────
|
|
551
|
+
if (!logicPayload || !finalText || finalText.trim().length < 100) {
|
|
552
|
+
push({ stage: 3, label: "Single-pass fallback synthesis (with source evidence)", ts: Date.now(), ok: true });
|
|
553
|
+
const fallbackPrompt = [
|
|
554
|
+
anchor.anchorStatement,
|
|
555
|
+
"",
|
|
556
|
+
constraintBlock,
|
|
557
|
+
"",
|
|
558
|
+
entitySheet.promptBlock,
|
|
559
|
+
artifactBlock ? `\n${artifactBlock}` : "",
|
|
560
|
+
"",
|
|
561
|
+
`STYLE PERSONA:\n${opts.persona.systemPromptFragment.split("\n").slice(0, 12).join("\n")}`,
|
|
562
|
+
opts.templateBlock ? `\n${opts.templateBlock}` : "",
|
|
563
|
+
sourceEvidenceBlock,
|
|
564
|
+
"",
|
|
565
|
+
"FINAL OUTPUT: write the answer directly, beginning with your most critical insight. No preamble, no outlines, no constraint labels. PRODUCE substantive content for every section — never leave a section header empty.",
|
|
566
|
+
].join("\n");
|
|
567
|
+
finalText = await generateSynthesizedResponse({
|
|
568
|
+
...opts.baseParams,
|
|
569
|
+
userMessage: `${opts.userQuery}\n\n${fallbackPrompt}`,
|
|
570
|
+
retrievedWebData: copywriterSources,
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// ── Stage 3.5: Adversarial routing (Tournament / Falsification / Gates) ──
|
|
575
|
+
// The draft is now routed THROUGH the adversarial critics before it can be
|
|
576
|
+
// emitted. This is where the 10/10 hardening happens.
|
|
577
|
+
const domain = opts.templateId === "OMEGA-SCIENCE" || opts.templateId === "NIH-GRANT-SRF" ? "science" : undefined;
|
|
578
|
+
let adversarialPasses: NDeepPassRecord[] | undefined;
|
|
579
|
+
let adversarialStable: boolean | undefined;
|
|
580
|
+
|
|
581
|
+
if (opts.nDeep) {
|
|
582
|
+
push({ stage: 5, label: "N-Deep: recursive adversarial refinement engaged", ts: Date.now(), ok: true });
|
|
583
|
+
const nd = await runNDeep({
|
|
584
|
+
userQuery: opts.userQuery,
|
|
585
|
+
initialDraft: finalText,
|
|
586
|
+
baseParams: { ...opts.baseParams, retrievedWebData: undefined, conversationHistory: [] },
|
|
587
|
+
domain,
|
|
588
|
+
rpm: opts.rpm,
|
|
589
|
+
maxPasses: opts.nDeepMaxPasses,
|
|
590
|
+
onTrace: push,
|
|
591
|
+
onDebug: (m) => push({ stage: 5, label: m, ts: Date.now(), ok: true }),
|
|
592
|
+
});
|
|
593
|
+
finalText = nd.finalText;
|
|
594
|
+
adversarialPasses = nd.passes;
|
|
595
|
+
adversarialStable = nd.stable;
|
|
596
|
+
push({ stage: 5, label: `N-Deep complete: ${nd.passes.length} pass(es), stable=${nd.stable}, ${nd.totalLlmCalls} LLM call(s)`, ts: Date.now(), ok: nd.stable });
|
|
597
|
+
} else {
|
|
598
|
+
// Single adversarial pass in standard 4-Stage mode.
|
|
599
|
+
// OOM GUARD: for large drafts (>15KB, typical for NIH grants with SLOOP/template),
|
|
600
|
+
// run ONLY deterministic structural gates (zero LLM calls, zero memory growth).
|
|
601
|
+
// The LLM red-team + repair cycle doubles working memory and causes the 140-260s OOM.
|
|
602
|
+
const draftIsLarge = finalText.length > 15_000;
|
|
603
|
+
if (draftIsLarge) {
|
|
604
|
+
push({ stage: 5, label: `Large draft (${finalText.length} chars) — deterministic gates only (skipping LLM red-team to prevent OOM)`, ts: Date.now(), ok: true });
|
|
605
|
+
const { runStructuralGates } = await import("./adversarial-engine");
|
|
606
|
+
const structural = runStructuralGates(finalText, { domain });
|
|
607
|
+
const blocking = structural.filter(d => d.severity === "critical" || d.severity === "major");
|
|
608
|
+
adversarialPasses = [{ pass: 1, model: opts.baseParams.model, defectCount: structural.length, criticalCount: blocking.length, verdict: blocking.length > 0 ? "revise" : "pass", defectTags: structural.map(d => `${d.severity}:${d.category}`), sectionsProposed: 0, sectionsAccepted: 0, sectionsRejected: 0, sectionsTieResolvedByIntelligence: 0, authorIntelligence: 0, judgeDecisions: [] }];
|
|
609
|
+
adversarialStable = blocking.length === 0;
|
|
610
|
+
push({ stage: 5, label: `Structural gates: ${structural.length} defect(s), ${blocking.length} blocking`, ts: Date.now(), ok: adversarialStable });
|
|
611
|
+
} else {
|
|
612
|
+
push({ stage: 5, label: "Adversarial single-pass red-team (Tournament + Falsification + Gates)", ts: Date.now(), ok: true });
|
|
613
|
+
const report = await runAdversarialRedTeam(finalText, opts.userQuery, opts.baseParams, {
|
|
614
|
+
domain,
|
|
615
|
+
rpm: opts.rpm,
|
|
616
|
+
onDebug: (m) => push({ stage: 5, label: m, ts: Date.now(), ok: true }),
|
|
617
|
+
});
|
|
618
|
+
const blocking = report.defects.filter((d) => d.severity === "critical" || d.severity === "major");
|
|
619
|
+
adversarialPasses = [{ pass: 1, model: opts.baseParams.model, defectCount: report.defects.length, criticalCount: blocking.length, verdict: report.verdict, defectTags: report.defects.map(d => `${d.severity}:${d.category}`), sectionsProposed: 0, sectionsAccepted: 0, sectionsRejected: 0, sectionsTieResolvedByIntelligence: 0, authorIntelligence: 0, judgeDecisions: [] }];
|
|
620
|
+
adversarialStable = report.verdict === "pass";
|
|
621
|
+
if (blocking.length > 0) {
|
|
622
|
+
push({ stage: 5, label: `Adversarial found ${blocking.length} blocking defect(s) — running one repair pass`, ts: Date.now(), ok: false, data: blocking.map((d) => d.id) });
|
|
623
|
+
// Cap repair prompt to prevent OOM from embedding full draft in repair context
|
|
624
|
+
const repairPrompt = `Revise the DRAFT to fix every listed defect. Keep what was correct. Fill ALL empty sections with substantive content. Output ONLY the corrected final answer — no commentary, no placeholders.\n\n${buildRepairBlock(report.defects)}\n\nUSER ASK: ${opts.userQuery}\n\nDRAFT:\n${finalText.slice(0, 20_000)}`;
|
|
625
|
+
try {
|
|
626
|
+
finalText = await throttle(
|
|
627
|
+
() => generateSynthesizedResponse({ ...opts.baseParams, userMessage: repairPrompt, retrievedWebData: copywriterSources.slice(0, 8), conversationHistory: [] }),
|
|
628
|
+
{ rpm: opts.rpm },
|
|
629
|
+
);
|
|
630
|
+
adversarialStable = true;
|
|
631
|
+
push({ stage: 5, label: "Adversarial repair pass applied ✓", ts: Date.now(), ok: true });
|
|
632
|
+
} catch (e) {
|
|
633
|
+
push({ stage: 5, label: `Adversarial repair failed: ${(e as Error).message}`, ts: Date.now(), ok: false });
|
|
634
|
+
}
|
|
635
|
+
} else {
|
|
636
|
+
push({ stage: 5, label: "Adversarial review: no blocking defects ✓", ts: Date.now(), ok: true });
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// ── Stage 4: Post-processing ─────────────────────────────────────────────
|
|
642
|
+
const cleaned = stage4Clean(finalText);
|
|
643
|
+
const sanitized = sanitizeOutput(cleaned);
|
|
644
|
+
push({ stage: 4, label: `Sanitizer: removed ${sanitized.removedSegments} leaked segment(s)`, ts: Date.now(), ok: true, data: sanitized.notes });
|
|
645
|
+
|
|
646
|
+
return {
|
|
647
|
+
computeRecords,
|
|
648
|
+
entitySheet,
|
|
649
|
+
artifactResponse,
|
|
650
|
+
finalText: sanitized.cleaned,
|
|
651
|
+
logicPayload,
|
|
652
|
+
anchor,
|
|
653
|
+
trace,
|
|
654
|
+
sanitizerRemovedSegments: sanitized.removedSegments,
|
|
655
|
+
usedMultiPass: !!logicPayload,
|
|
656
|
+
adversarialPasses,
|
|
657
|
+
adversarialStable,
|
|
658
|
+
};
|
|
659
|
+
}
|