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,592 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* N-Deep v4 — Section-Targeted Adversarial Refinement with Batched Judge
|
|
3
|
+
*
|
|
4
|
+
* v4 memory/bandwidth fixes over v3:
|
|
5
|
+
* 1. DRAFT DIGEST: critic receives a structural digest (section headers +
|
|
6
|
+
* first/last 200 chars) instead of the full draft body. Peak input tokens
|
|
7
|
+
* drop from O(|draft|) to O(√|draft|). Full section text is only sent
|
|
8
|
+
* when the critic requests a revision on that specific section.
|
|
9
|
+
* 2. BATCHED JUDGE: all revision decisions are made in ONE LLM call instead
|
|
10
|
+
* of N sequential calls. Holds only the batch prompt (≤ 24KB) in memory
|
|
11
|
+
* vs. N × (original + revised) strings simultaneously.
|
|
12
|
+
* 3. RESPONSE CAP: raw critic output is immediately sliced to MAX_RAW_CHARS
|
|
13
|
+
* before parsing, preventing allocation spikes from runaway responses.
|
|
14
|
+
* 4. SECTION ISOLATION: only the sections with accepted revisions are spliced;
|
|
15
|
+
* the rest of the draft is referenced by index, never duplicated.
|
|
16
|
+
* 5. FULL REWRITE GATE: only triggered by judge's REWRITE_CORE verdict;
|
|
17
|
+
* hard-capped at 1 per run.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { GenerateParams, ModelId } from "./models";
|
|
21
|
+
import { generateSynthesizedResponse } from "./models";
|
|
22
|
+
import { runAdversarialRedTeam, buildRepairBlock } from "./adversarial-engine";
|
|
23
|
+
import { throttle } from "./rpm-governor";
|
|
24
|
+
import type { PipelineTrace } from "./pipeline";
|
|
25
|
+
import { readMemoryReport, safeDraftCharCap, settleHeap, shouldSkipAdversarial } from "./memory-governor";
|
|
26
|
+
import { intelligenceOf, compareIntelligence } from "./model-intelligence";
|
|
27
|
+
|
|
28
|
+
// ─── Model rotation: strongest at first & last ───────────────────────────────
|
|
29
|
+
const ROTATION_GEMINI: ModelId[] = [
|
|
30
|
+
"gemini-3.5-flash",
|
|
31
|
+
"gemma-4-31b-it",
|
|
32
|
+
"gemini-2.5-flash-lite",
|
|
33
|
+
"gemma-3-27b-it",
|
|
34
|
+
"gemini-3.1-flash-lite",
|
|
35
|
+
"gemma-4-26b-it",
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
function modelForPass(provider: string, pass: number, cap: number, baseModel: ModelId): ModelId {
|
|
39
|
+
if (provider !== "gemini") return baseModel;
|
|
40
|
+
const last = pass === cap;
|
|
41
|
+
if (pass === 1 || last) return ROTATION_GEMINI[0];
|
|
42
|
+
const mid = (pass - 2) % (ROTATION_GEMINI.length - 1) + 1;
|
|
43
|
+
return ROTATION_GEMINI[mid];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
47
|
+
const ABS_MAX_PASSES = 20;
|
|
48
|
+
const DEFAULT_MAX_PASSES = 4;
|
|
49
|
+
const MAX_SECTION_CHARS = 6_000; // hard cap per proposed revision block
|
|
50
|
+
const MAX_REVISIONS_PER_PASS = 5; // hard cap critic can emit per pass
|
|
51
|
+
const MAX_FULL_REWRITES = 1; // judge-triggered full rewrites per run
|
|
52
|
+
const MAX_RAW_RESPONSE = 32_000; // immediate cap on raw LLM response string
|
|
53
|
+
const DIGEST_SNIPPET_CHARS = 200; // chars of section start/end shown to critic
|
|
54
|
+
const MAX_DRAFT_TO_CRITIC = 14_000; // max chars of full draft exposed to critic
|
|
55
|
+
|
|
56
|
+
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
export interface NDeepPassSummary {
|
|
59
|
+
pass: number;
|
|
60
|
+
model: ModelId;
|
|
61
|
+
judgeModel?: ModelId;
|
|
62
|
+
defectCount: number;
|
|
63
|
+
criticalCount: number;
|
|
64
|
+
verdict: "pass" | "revise" | "rewrite-core";
|
|
65
|
+
defectTags: string[];
|
|
66
|
+
sectionsProposed: number;
|
|
67
|
+
sectionsAccepted: number;
|
|
68
|
+
sectionsRejected: number;
|
|
69
|
+
sectionsTieResolvedByIntelligence: number;
|
|
70
|
+
authorIntelligence: number;
|
|
71
|
+
judgeDecisions: Array<{
|
|
72
|
+
section: string;
|
|
73
|
+
decision: "accept" | "reject" | "tie";
|
|
74
|
+
tieWinner?: "candidate" | "original";
|
|
75
|
+
reason: string;
|
|
76
|
+
}>;
|
|
77
|
+
deathCertificate?: { chars: number; hash: string; reason: string };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface NDeepResult {
|
|
81
|
+
finalText: string;
|
|
82
|
+
passes: NDeepPassSummary[];
|
|
83
|
+
stable: boolean;
|
|
84
|
+
totalLlmCalls: number;
|
|
85
|
+
fullRewrites: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface NDeepOpts {
|
|
89
|
+
userQuery: string;
|
|
90
|
+
initialDraft: string;
|
|
91
|
+
fullSloopReport?: boolean;
|
|
92
|
+
baseParams: GenerateParams;
|
|
93
|
+
domain?: string;
|
|
94
|
+
rpm?: number;
|
|
95
|
+
maxPasses?: number;
|
|
96
|
+
judgeModel?: ModelId;
|
|
97
|
+
onTrace?: (t: PipelineTrace) => void;
|
|
98
|
+
onDebug?: (m: string) => void;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ─── Draft utilities ──────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
function capDraft(text: string): string {
|
|
104
|
+
const cap = safeDraftCharCap(readMemoryReport());
|
|
105
|
+
return text.length > cap ? String(text.slice(0, cap)) : text;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function cheapHash(text: string): string {
|
|
109
|
+
let h = 2166136261;
|
|
110
|
+
for (let i = 0; i < text.length; i++) {
|
|
111
|
+
h ^= text.charCodeAt(i);
|
|
112
|
+
h = Math.imul(h, 16777619);
|
|
113
|
+
}
|
|
114
|
+
return (h >>> 0).toString(16).padStart(8, "0");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function pruneParams(params: GenerateParams): GenerateParams {
|
|
118
|
+
return { ...params, retrievedWebData: undefined, conversationHistory: [] };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Build a structural DIGEST of the draft for the critic.
|
|
123
|
+
* Critic gets: section headings + first/last DIGEST_SNIPPET_CHARS of each
|
|
124
|
+
* section. Full text is only provided for sections targeted for revision.
|
|
125
|
+
* This keeps the critic input to ~O(sections × 400) chars vs O(|draft|).
|
|
126
|
+
*/
|
|
127
|
+
function buildDraftDigest(draft: string): string {
|
|
128
|
+
// Split on markdown section headings (##) or double-newlines for plain text
|
|
129
|
+
const sections = draft.split(/(?=^## )/m);
|
|
130
|
+
if (sections.length <= 1) {
|
|
131
|
+
// Non-sectioned: just show head + tail
|
|
132
|
+
const head = draft.slice(0, 1_200);
|
|
133
|
+
const tail = draft.length > 1_200 ? "\n…\n" + draft.slice(-600) : "";
|
|
134
|
+
return String(head + tail);
|
|
135
|
+
}
|
|
136
|
+
return sections.map(sec => {
|
|
137
|
+
const lines = sec.trimStart();
|
|
138
|
+
if (lines.length <= DIGEST_SNIPPET_CHARS * 2 + 60) return lines; // short enough, show all
|
|
139
|
+
const head = lines.slice(0, DIGEST_SNIPPET_CHARS);
|
|
140
|
+
const tail = lines.slice(-DIGEST_SNIPPET_CHARS);
|
|
141
|
+
return String(`${head}\n[…${lines.length - DIGEST_SNIPPET_CHARS * 2} chars…]\n${tail}`);
|
|
142
|
+
}).join("\n\n");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ─── Section revision parsing ─────────────────────────────────────────────────
|
|
146
|
+
|
|
147
|
+
interface SectionRevision {
|
|
148
|
+
anchor: string;
|
|
149
|
+
original: string;
|
|
150
|
+
revised: string;
|
|
151
|
+
reason: string;
|
|
152
|
+
idx: number; // 0-based revision index for batch judge
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function parseSectionRevisions(raw: string, draft: string): SectionRevision[] {
|
|
156
|
+
if (!raw) return [];
|
|
157
|
+
// Immediately cap: prevents parse of runaway responses from consuming heap
|
|
158
|
+
const capped = raw.slice(0, MAX_RAW_RESPONSE);
|
|
159
|
+
const out: SectionRevision[] = [];
|
|
160
|
+
const blockRe = /<<<REVISE>>>([\s\S]*?)<<<END>>>/g;
|
|
161
|
+
let m: RegExpExecArray | null;
|
|
162
|
+
let idx = 0;
|
|
163
|
+
while ((m = blockRe.exec(capped)) !== null && out.length < MAX_REVISIONS_PER_PASS) {
|
|
164
|
+
const body = m[1] || "";
|
|
165
|
+
const anchorMatch = body.match(/ANCHOR:\s*([^\n]+)/);
|
|
166
|
+
const split = body.split(/<<<TO>>>/);
|
|
167
|
+
if (split.length !== 2) continue;
|
|
168
|
+
const origPart = split[0].replace(/[\s\S]*?ORIGINAL:\s*/, "").trim();
|
|
169
|
+
const revPart = split[1].replace(/[\s\S]*?REVISED:\s*/, "");
|
|
170
|
+
const reasonMatch = revPart.match(/REASON:\s*([^\n]+)/);
|
|
171
|
+
const revised = revPart.replace(/REASON:[\s\S]*$/, "").trim();
|
|
172
|
+
if (!revised) continue;
|
|
173
|
+
|
|
174
|
+
// If critic gave us no ORIGINAL text (digest mode — expected), locate it
|
|
175
|
+
// from the draft via the anchor
|
|
176
|
+
let original = origPart.slice(0, MAX_SECTION_CHARS);
|
|
177
|
+
if (!original && anchorMatch?.[1]) {
|
|
178
|
+
const anchor = anchorMatch[1].trim().slice(0, 80);
|
|
179
|
+
const pos = draft.indexOf(anchor);
|
|
180
|
+
if (pos !== -1) {
|
|
181
|
+
// Extract paragraph starting at anchor (up to 4KB)
|
|
182
|
+
const end = draft.slice(pos).search(/\n\s*\n/);
|
|
183
|
+
original = draft.slice(pos, end === -1 ? pos + MAX_SECTION_CHARS : pos + end);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
out.push({
|
|
187
|
+
anchor: (anchorMatch?.[1] || original.slice(0, 80)).trim().slice(0, 120),
|
|
188
|
+
original: original.slice(0, MAX_SECTION_CHARS),
|
|
189
|
+
revised: revised.slice(0, MAX_SECTION_CHARS),
|
|
190
|
+
reason: (reasonMatch?.[1] || "no reason given").trim().slice(0, 200),
|
|
191
|
+
idx,
|
|
192
|
+
});
|
|
193
|
+
idx++;
|
|
194
|
+
}
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function spliceSection(draft: string, original: string, revised: string): { next: string; applied: boolean } {
|
|
199
|
+
if (!original) return { next: draft, applied: false };
|
|
200
|
+
const idx = draft.indexOf(original);
|
|
201
|
+
if (idx !== -1) {
|
|
202
|
+
return { next: String(draft.slice(0, idx) + revised + draft.slice(idx + original.length)), applied: true };
|
|
203
|
+
}
|
|
204
|
+
// Fuzzy: anchor-based paragraph replacement
|
|
205
|
+
const anchor = original.slice(0, 60);
|
|
206
|
+
const ai = draft.indexOf(anchor);
|
|
207
|
+
if (ai === -1) return { next: draft, applied: false };
|
|
208
|
+
const endRel = draft.slice(ai).search(/\n\s*\n/);
|
|
209
|
+
const end = endRel === -1 ? draft.length : ai + endRel;
|
|
210
|
+
return { next: String(draft.slice(0, ai) + revised + draft.slice(end)), applied: true };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ─── Batched Judge ─────────────────────────────────────────────────────────────
|
|
214
|
+
// ONE LLM call for ALL revisions in a pass. Prompt contains numbered pairs.
|
|
215
|
+
// Judge returns one line per revision: "N: accept|reject|tie [CORE] reason"
|
|
216
|
+
|
|
217
|
+
interface BatchJudgeResult {
|
|
218
|
+
decisions: Array<{
|
|
219
|
+
decision: "accept" | "reject" | "tie";
|
|
220
|
+
rewriteCore: boolean;
|
|
221
|
+
reason: string;
|
|
222
|
+
tieWinner?: "candidate" | "original";
|
|
223
|
+
}>;
|
|
224
|
+
anyRewriteCore: boolean;
|
|
225
|
+
coreReason: string;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function parseBatchJudgeReply(raw: string, revisions: SectionRevision[], criticModel: ModelId, authorModel: ModelId): BatchJudgeResult {
|
|
229
|
+
const capped = String(raw.slice(0, 8_000));
|
|
230
|
+
const lines = capped.split("\n").filter(l => /^\d+\s*:/.test(l.trim()));
|
|
231
|
+
const decisions = revisions.map((_r, i) => {
|
|
232
|
+
const line = lines.find(l => l.trim().startsWith(`${i + 1}:`)) || "";
|
|
233
|
+
const lower = line.toLowerCase();
|
|
234
|
+
const rewriteCore = /\[core\]/.test(lower);
|
|
235
|
+
let decision: "accept" | "reject" | "tie" = "tie";
|
|
236
|
+
if (/:\s*accept/.test(lower)) decision = "accept";
|
|
237
|
+
else if (/:\s*reject/.test(lower)) decision = "reject";
|
|
238
|
+
// Tie-break by intelligence
|
|
239
|
+
let tieWinner: "candidate" | "original" | undefined;
|
|
240
|
+
if (decision === "tie") {
|
|
241
|
+
const cmp = compareIntelligence(criticModel, authorModel);
|
|
242
|
+
tieWinner = cmp >= 0 ? "candidate" : "original";
|
|
243
|
+
}
|
|
244
|
+
const reasonMatch = line.match(/:\s*(?:accept|reject|tie)[^:]*?(?:\[core\])?\s*(.*)/i);
|
|
245
|
+
return {
|
|
246
|
+
decision,
|
|
247
|
+
rewriteCore,
|
|
248
|
+
reason: (reasonMatch?.[1] || line).trim().slice(0, 180),
|
|
249
|
+
tieWinner,
|
|
250
|
+
};
|
|
251
|
+
});
|
|
252
|
+
const anyRewriteCore = decisions.some(d => d.rewriteCore);
|
|
253
|
+
const coreReason = decisions.find(d => d.rewriteCore)?.reason || "";
|
|
254
|
+
return { decisions, anyRewriteCore, coreReason };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async function batchJudgeRevisions(opts: {
|
|
258
|
+
judgeParams: GenerateParams;
|
|
259
|
+
userQuery: string;
|
|
260
|
+
revisions: SectionRevision[];
|
|
261
|
+
criticModel: ModelId;
|
|
262
|
+
authorModel: ModelId;
|
|
263
|
+
rpm?: number;
|
|
264
|
+
onDebug?: (m: string) => void;
|
|
265
|
+
}): Promise<BatchJudgeResult> {
|
|
266
|
+
if (opts.revisions.length === 0) {
|
|
267
|
+
return { decisions: [], anyRewriteCore: false, coreReason: "" };
|
|
268
|
+
}
|
|
269
|
+
// Build ONE compact prompt with all numbered revision pairs
|
|
270
|
+
const pairs = opts.revisions.map((r, i) => [
|
|
271
|
+
`--- REVISION ${i + 1} (anchor: "${r.anchor.slice(0, 60)}") ---`,
|
|
272
|
+
`CRITIC REASON: ${r.reason}`,
|
|
273
|
+
`ORIGINAL (first 400 chars): ${r.original.slice(0, 400)}`,
|
|
274
|
+
`REVISED (first 400 chars): ${r.revised.slice(0, 400)}`,
|
|
275
|
+
].join("\n")).join("\n\n");
|
|
276
|
+
|
|
277
|
+
const prompt = [
|
|
278
|
+
`You are a BATCH JUDGE evaluating ${opts.revisions.length} proposed section revision(s).`,
|
|
279
|
+
`For EACH revision, reply with EXACTLY ONE line in this format:`,
|
|
280
|
+
`N: accept|reject|tie [CORE if original section's core idea is fundamentally wrong] <short reason>`,
|
|
281
|
+
``,
|
|
282
|
+
`Rules:`,
|
|
283
|
+
` - Use "accept" if the revision is clearly better.`,
|
|
284
|
+
` - Use "reject" if the original is better or the revision is off-topic.`,
|
|
285
|
+
` - Use "tie" if you genuinely cannot decide (tie-break is handled externally).`,
|
|
286
|
+
` - Add [CORE] ONLY if the entire section's core idea is wrong and needs full redraft.`,
|
|
287
|
+
` - Output ONLY the N numbered lines, nothing else.`,
|
|
288
|
+
``,
|
|
289
|
+
`USER QUESTION: ${opts.userQuery.slice(0, 200)}`,
|
|
290
|
+
``,
|
|
291
|
+
pairs,
|
|
292
|
+
``,
|
|
293
|
+
`Reply with ${opts.revisions.length} numbered line(s) only:`,
|
|
294
|
+
].join("\n");
|
|
295
|
+
|
|
296
|
+
try {
|
|
297
|
+
const raw = await throttle(
|
|
298
|
+
() => generateSynthesizedResponse({ ...opts.judgeParams, userMessage: prompt, conversationHistory: [] }),
|
|
299
|
+
{ rpm: opts.rpm, onWait: ms => opts.onDebug?.(`[Judge batch] RPM wait ${ms}ms`) },
|
|
300
|
+
);
|
|
301
|
+
return parseBatchJudgeReply(raw, opts.revisions, opts.criticModel, opts.authorModel);
|
|
302
|
+
} catch (e) {
|
|
303
|
+
opts.onDebug?.(`[Judge batch] error: ${(e as Error).message} — defaulting all to tie`);
|
|
304
|
+
const cmpFallback = compareIntelligence(opts.criticModel, opts.authorModel);
|
|
305
|
+
const tieWinnerFallback: "candidate" | "original" = cmpFallback >= 0 ? "candidate" : "original";
|
|
306
|
+
return {
|
|
307
|
+
decisions: opts.revisions.map(() => ({
|
|
308
|
+
decision: "tie" as const, rewriteCore: false, reason: "judge error fallback", tieWinner: tieWinnerFallback,
|
|
309
|
+
})),
|
|
310
|
+
anyRewriteCore: false,
|
|
311
|
+
coreReason: "",
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ─── Critic: emits section revisions from DIGEST only ────────────────────────
|
|
317
|
+
|
|
318
|
+
async function emitSectionRevisions(opts: {
|
|
319
|
+
criticParams: GenerateParams;
|
|
320
|
+
userQuery: string;
|
|
321
|
+
draftDigest: string;
|
|
322
|
+
defectsBlock: string;
|
|
323
|
+
rpm?: number;
|
|
324
|
+
fullSloopReport?: boolean;
|
|
325
|
+
onDebug?: (m: string) => void;
|
|
326
|
+
}): Promise<{ raw: string }> {
|
|
327
|
+
const prompt = [
|
|
328
|
+
`You are a LOCALIZED REVISION EDITOR. You receive a STRUCTURAL DIGEST of a draft (section headers + snippets, NOT the full text).`,
|
|
329
|
+
`Do NOT rewrite the entire document. For each defect, emit ONE bounded replacement block.`,
|
|
330
|
+
opts.fullSloopReport ? `The draft is a multi-section SLOOP report. Preserve all sections you do not touch.` : "",
|
|
331
|
+
``,
|
|
332
|
+
`EXACT OUTPUT FORMAT (repeat for each defect you fix):`,
|
|
333
|
+
`<<<REVISE>>>`,
|
|
334
|
+
`ANCHOR: <first ~60 chars of the section heading or opening sentence you are revising>`,
|
|
335
|
+
`ORIGINAL:`,
|
|
336
|
+
`<the exact existing text span to replace — copy it verbatim from your knowledge of the section, ≤${MAX_SECTION_CHARS} chars>`,
|
|
337
|
+
`<<<TO>>>`,
|
|
338
|
+
`REVISED:`,
|
|
339
|
+
`<your improved replacement, ≤${MAX_SECTION_CHARS} chars>`,
|
|
340
|
+
`REASON: <one sentence>`,
|
|
341
|
+
`<<<END>>>`,
|
|
342
|
+
``,
|
|
343
|
+
`Hard rules:`,
|
|
344
|
+
` • AT MOST ${MAX_REVISIONS_PER_PASS} blocks. Fix only the most critical defects.`,
|
|
345
|
+
` • If you cannot identify exact original text from the digest, use ANCHOR only and leave ORIGINAL blank — the system will locate it.`,
|
|
346
|
+
` • Do NOT output any content outside <<<REVISE>>> blocks.`,
|
|
347
|
+
` • Do NOT restate the full document.`,
|
|
348
|
+
``,
|
|
349
|
+
`USER ASK: ${opts.userQuery.slice(0, 300)}`,
|
|
350
|
+
``,
|
|
351
|
+
opts.defectsBlock,
|
|
352
|
+
``,
|
|
353
|
+
`DRAFT DIGEST (section headers + snippets):`,
|
|
354
|
+
opts.draftDigest,
|
|
355
|
+
].filter(Boolean).join("\n");
|
|
356
|
+
|
|
357
|
+
opts.onDebug?.(`[N-Deep critic] sending digest (${opts.draftDigest.length} chars, full draft not sent)`);
|
|
358
|
+
const raw = await throttle(
|
|
359
|
+
() => generateSynthesizedResponse({ ...opts.criticParams, userMessage: prompt, conversationHistory: [] }),
|
|
360
|
+
{ rpm: opts.rpm, onWait: ms => opts.onDebug?.(`[N-Deep critic] RPM wait ${ms}ms`) },
|
|
361
|
+
);
|
|
362
|
+
return { raw: String(raw.slice(0, MAX_RAW_RESPONSE)) }; // immediate cap + flatten
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// ─── Main loop ────────────────────────────────────────────────────────────────
|
|
366
|
+
|
|
367
|
+
export async function runNDeep(opts: NDeepOpts): Promise<NDeepResult> {
|
|
368
|
+
const cap = Math.min(ABS_MAX_PASSES, Math.max(1, opts.maxPasses ?? DEFAULT_MAX_PASSES));
|
|
369
|
+
const passes: NDeepPassSummary[] = [];
|
|
370
|
+
let llmCalls = 0;
|
|
371
|
+
let stable = false;
|
|
372
|
+
let fullRewrites = 0;
|
|
373
|
+
const originalIntent = opts.userQuery;
|
|
374
|
+
const cohesionHistory: string[] = [];
|
|
375
|
+
const judgeModel: ModelId = opts.judgeModel || opts.baseParams.model;
|
|
376
|
+
const authorModel: ModelId = opts.baseParams.model;
|
|
377
|
+
const authorIntelligence = intelligenceOf(authorModel);
|
|
378
|
+
|
|
379
|
+
let current: string = capDraft(opts.initialDraft);
|
|
380
|
+
const prunedParams = pruneParams(opts.baseParams);
|
|
381
|
+
opts.onDebug?.(opts.fullSloopReport
|
|
382
|
+
? `[N-Deep v4] SLOOP writeup (${current.length} chars) — digest mode, ${cap} passes, judge=${judgeModel}`
|
|
383
|
+
: `[N-Deep v4] section-targeted refinement (${current.length} chars, ${cap} passes, judge=${judgeModel})`);
|
|
384
|
+
|
|
385
|
+
for (let pass = 1; pass <= cap; pass++) {
|
|
386
|
+
const passModel = modelForPass(opts.baseParams.provider, pass, cap, authorModel);
|
|
387
|
+
const passParams: GenerateParams = { ...prunedParams, model: passModel };
|
|
388
|
+
const judgeParams: GenerateParams = { ...prunedParams, model: judgeModel };
|
|
389
|
+
const criticIntel = intelligenceOf(passModel);
|
|
390
|
+
|
|
391
|
+
opts.onDebug?.(`[N-Deep ${pass}/${cap}] critic=${passModel}(${criticIntel}) judge=${judgeModel}`);
|
|
392
|
+
|
|
393
|
+
// ── STEP 1: Adversarial structural critique (on digest to save tokens) ──
|
|
394
|
+
const memNow = readMemoryReport();
|
|
395
|
+
const critiqueInput = shouldSkipAdversarial(current.length, memNow)
|
|
396
|
+
? current.slice(0, 8_000)
|
|
397
|
+
: current.length > MAX_DRAFT_TO_CRITIC
|
|
398
|
+
? current.slice(0, MAX_DRAFT_TO_CRITIC)
|
|
399
|
+
: current;
|
|
400
|
+
|
|
401
|
+
let report = await runAdversarialRedTeam(
|
|
402
|
+
critiqueInput,
|
|
403
|
+
opts.userQuery,
|
|
404
|
+
passParams,
|
|
405
|
+
{ domain: opts.domain, rpm: opts.rpm, onDebug: opts.onDebug },
|
|
406
|
+
);
|
|
407
|
+
llmCalls += 1;
|
|
408
|
+
|
|
409
|
+
const critical = report.defects.filter(d => d.severity === "critical" || d.severity === "major");
|
|
410
|
+
const summary: NDeepPassSummary = {
|
|
411
|
+
pass,
|
|
412
|
+
model: passModel,
|
|
413
|
+
judgeModel,
|
|
414
|
+
defectCount: report.defects.length,
|
|
415
|
+
criticalCount: critical.length,
|
|
416
|
+
verdict: report.verdict,
|
|
417
|
+
defectTags: report.defects.map(d => `${d.severity}:${d.category}`),
|
|
418
|
+
sectionsProposed: 0,
|
|
419
|
+
sectionsAccepted: 0,
|
|
420
|
+
sectionsRejected: 0,
|
|
421
|
+
sectionsTieResolvedByIntelligence: 0,
|
|
422
|
+
authorIntelligence,
|
|
423
|
+
judgeDecisions: [],
|
|
424
|
+
};
|
|
425
|
+
passes.push(summary);
|
|
426
|
+
|
|
427
|
+
opts.onTrace?.({
|
|
428
|
+
stage: 5 + pass / 10,
|
|
429
|
+
label: `N-Deep ${pass}/${cap} [${passModel}]: ${report.verdict} — ${critical.length} blocking`,
|
|
430
|
+
ts: Date.now(),
|
|
431
|
+
ok: report.verdict === "pass",
|
|
432
|
+
data: summary.defectTags,
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
if (report.verdict === "pass") {
|
|
436
|
+
stable = true;
|
|
437
|
+
opts.onDebug?.(`[N-Deep] stable at pass ${pass}`);
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const defectsBlock = buildRepairBlock(report.defects);
|
|
442
|
+
cohesionHistory.push(`P${pass}:REVISE[${summary.defectTags.slice(0, 4).join(",") || "none"}]`);
|
|
443
|
+
// Free the report immediately — large rawCritique string
|
|
444
|
+
report = { verdict: "revise" as const, defects: [], rawCritique: "" };
|
|
445
|
+
|
|
446
|
+
if (pass === cap) {
|
|
447
|
+
opts.onDebug?.(`[N-Deep] hit cap ${cap} — ${summary.criticalCount} blocking remain`);
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// ── STEP 2: Critic emits localized REVISE blocks from DIGEST (not full draft) ──
|
|
452
|
+
const draftDigest = buildDraftDigest(current);
|
|
453
|
+
let revisions: SectionRevision[] = [];
|
|
454
|
+
try {
|
|
455
|
+
const { raw } = await emitSectionRevisions({
|
|
456
|
+
criticParams: passParams,
|
|
457
|
+
userQuery: originalIntent,
|
|
458
|
+
draftDigest,
|
|
459
|
+
defectsBlock,
|
|
460
|
+
rpm: opts.rpm,
|
|
461
|
+
fullSloopReport: opts.fullSloopReport,
|
|
462
|
+
onDebug: opts.onDebug,
|
|
463
|
+
});
|
|
464
|
+
revisions = parseSectionRevisions(raw, current);
|
|
465
|
+
llmCalls += 1;
|
|
466
|
+
} catch (e) {
|
|
467
|
+
opts.onDebug?.(`[N-Deep] critic failed: ${(e as Error).message} — skipping pass`);
|
|
468
|
+
await settleHeap(15);
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
summary.sectionsProposed = revisions.length;
|
|
473
|
+
opts.onDebug?.(`[N-Deep ${pass}/${cap}] critic proposed ${revisions.length} revision(s)`);
|
|
474
|
+
|
|
475
|
+
if (revisions.length === 0) {
|
|
476
|
+
cohesionHistory.push(`P${pass}:NO_REVISIONS`);
|
|
477
|
+
await settleHeap(15);
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// ── STEP 3: ONE batched judge call for ALL revisions ──────────────────────
|
|
482
|
+
const batchResult = await batchJudgeRevisions({
|
|
483
|
+
judgeParams,
|
|
484
|
+
userQuery: originalIntent,
|
|
485
|
+
revisions,
|
|
486
|
+
criticModel: passModel,
|
|
487
|
+
authorModel,
|
|
488
|
+
rpm: opts.rpm,
|
|
489
|
+
onDebug: opts.onDebug,
|
|
490
|
+
});
|
|
491
|
+
llmCalls += 1;
|
|
492
|
+
|
|
493
|
+
// ── STEP 4: Full rewrite only for explicit, hard core rejection ───────────
|
|
494
|
+
const hardCoreRewrite = batchResult.anyRewriteCore && (
|
|
495
|
+
summary.criticalCount >= 6 ||
|
|
496
|
+
/(GATE-DELIVERY-CONTRADICTION|GATE-STEPPED-WEDGE-VOID|GATE-CRISIS-ESCALATION-LIABILITY|GATE-PLACEHOLDER|GATE-META-TEXT-LEAK|core idea rejected|fundamental(?:ly)? wrong|unsalvageable)/i.test(`${defectsBlock}\n${batchResult.coreReason}`)
|
|
497
|
+
);
|
|
498
|
+
if (hardCoreRewrite && fullRewrites < MAX_FULL_REWRITES) {
|
|
499
|
+
fullRewrites += 1;
|
|
500
|
+
summary.verdict = "rewrite-core";
|
|
501
|
+
opts.onDebug?.(`[N-Deep] CORE REWRITE triggered (${fullRewrites}/${MAX_FULL_REWRITES}): ${batchResult.coreReason}`);
|
|
502
|
+
const prevLen = current.length;
|
|
503
|
+
const prevHash = cheapHash(current);
|
|
504
|
+
const prevDraft = current;
|
|
505
|
+
current = "";
|
|
506
|
+
let rewritePrompt: string = [
|
|
507
|
+
`The CORE IDEA was rejected: ${batchResult.coreReason}`,
|
|
508
|
+
`Rewrite the draft to fix the core issue while preserving the user's intent.`,
|
|
509
|
+
`Keep correct factual content. Output ONLY the new draft.`,
|
|
510
|
+
`USER INTENT: ${originalIntent}`,
|
|
511
|
+
`DEFECTS: ${defectsBlock}`,
|
|
512
|
+
`PRIOR DRAFT (for reference):`,
|
|
513
|
+
String(prevDraft.slice(0, 12_000)),
|
|
514
|
+
].join("\n");
|
|
515
|
+
try {
|
|
516
|
+
const rewritten = await throttle(
|
|
517
|
+
() => generateSynthesizedResponse({ ...passParams, userMessage: rewritePrompt, conversationHistory: [] }),
|
|
518
|
+
{ rpm: opts.rpm, onWait: ms => opts.onDebug?.(`[N-Deep rewrite] RPM wait ${ms}ms`) },
|
|
519
|
+
);
|
|
520
|
+
rewritePrompt = "";
|
|
521
|
+
llmCalls += 1;
|
|
522
|
+
if (rewritten && rewritten.trim().length >= prevLen * 0.5) {
|
|
523
|
+
current = capDraft(rewritten);
|
|
524
|
+
cohesionHistory.push(`P${pass}:CORE_REWRITTEN(${prevLen}->${current.length})`);
|
|
525
|
+
summary.deathCertificate = { chars: prevLen, hash: prevHash, reason: `core_rewrite_pass_${pass}` };
|
|
526
|
+
} else {
|
|
527
|
+
current = prevDraft;
|
|
528
|
+
cohesionHistory.push(`P${pass}:CORE_REWRITE_REJECTED(too_short)`);
|
|
529
|
+
opts.onDebug?.(`[N-Deep] core rewrite collapsed — keeping prior draft`);
|
|
530
|
+
}
|
|
531
|
+
} catch (e) {
|
|
532
|
+
rewritePrompt = "";
|
|
533
|
+
current = prevDraft;
|
|
534
|
+
opts.onDebug?.(`[N-Deep] core rewrite failed: ${(e as Error).message}`);
|
|
535
|
+
}
|
|
536
|
+
} else {
|
|
537
|
+
// ── STEP 5: Splice accepted section revisions one-by-one ─────────────────
|
|
538
|
+
let coreRejectedBudgetExhausted = batchResult.anyRewriteCore && fullRewrites >= MAX_FULL_REWRITES;
|
|
539
|
+
for (let ri = 0; ri < revisions.length; ri++) {
|
|
540
|
+
const r = revisions[ri];
|
|
541
|
+
const jd = batchResult.decisions[ri];
|
|
542
|
+
if (!jd) continue;
|
|
543
|
+
|
|
544
|
+
if (jd.rewriteCore && !coreRejectedBudgetExhausted) continue; // handled above
|
|
545
|
+
|
|
546
|
+
let apply = false;
|
|
547
|
+
let tieWinner: "candidate" | "original" | undefined;
|
|
548
|
+
if (jd.decision === "accept") {
|
|
549
|
+
apply = true;
|
|
550
|
+
} else if (jd.decision === "reject") {
|
|
551
|
+
apply = false;
|
|
552
|
+
} else {
|
|
553
|
+
// TIE: intelligence tiebreak (already computed in parseBatchJudgeReply)
|
|
554
|
+
tieWinner = jd.tieWinner;
|
|
555
|
+
apply = tieWinner === "candidate";
|
|
556
|
+
summary.sectionsTieResolvedByIntelligence += 1;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
summary.judgeDecisions.push({
|
|
560
|
+
section: r.anchor,
|
|
561
|
+
decision: jd.decision,
|
|
562
|
+
tieWinner,
|
|
563
|
+
reason: jd.reason,
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
if (apply && r.original) {
|
|
567
|
+
const { next, applied } = spliceSection(current, r.original, r.revised);
|
|
568
|
+
if (applied) {
|
|
569
|
+
current = capDraft(next);
|
|
570
|
+
summary.sectionsAccepted += 1;
|
|
571
|
+
opts.onDebug?.(`[N-Deep] section accepted (${r.original.length}→${r.revised.length} chars)`);
|
|
572
|
+
} else {
|
|
573
|
+
summary.sectionsRejected += 1;
|
|
574
|
+
opts.onDebug?.(`[N-Deep] revision unanchorable — skipped`);
|
|
575
|
+
}
|
|
576
|
+
} else {
|
|
577
|
+
summary.sectionsRejected += 1;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
cohesionHistory.push(
|
|
582
|
+
`P${pass}:ACC=${summary.sectionsAccepted}/REJ=${summary.sectionsRejected}/TIE=${summary.sectionsTieResolvedByIntelligence}`
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
await settleHeap(15);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
return { finalText: String(current), passes, stable, totalLlmCalls: llmCalls, fullRewrites };
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
export type { NDeepPassSummary as NDeepPassRecord };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* N-Deep — persistent workspace override (Vite interceptor pattern).
|
|
3
|
+
*
|
|
4
|
+
* The base `runNDeep()` (real production adversarial refinement engine, used
|
|
5
|
+
* directly by ChatApp.tsx's "⚡ N-Deep" toggle AND by lib/pipeline.ts's 4-Stage
|
|
6
|
+
* Stage 3.5 routing) already benefits from the truncation gate added to
|
|
7
|
+
* `./adversarial-engine.ts` (its per-pass critique step now correctly flags a
|
|
8
|
+
* truncated draft as "revise" instead of a false "pass"). This closes most of
|
|
9
|
+
* the truncation-slips-through-N-Deep gap for free.
|
|
10
|
+
*
|
|
11
|
+
* Residual gap: if the pass BUDGET is exhausted (`pass === cap`) while the
|
|
12
|
+
* draft is STILL truncated, the base loop breaks with `stable: false` and
|
|
13
|
+
* returns the truncated text as-is — the caller then ships it unchanged. Per
|
|
14
|
+
* the standing product requirement ("always rewrite, never block/ship a
|
|
15
|
+
* truncated answer"), this wrapper adds ONE bounded completion-repair call
|
|
16
|
+
* that fires ONLY in that rare residual case, and is REJECTED (original text
|
|
17
|
+
* kept) unless the repair is both longer and verifiably non-truncated —
|
|
18
|
+
* a strict, monotonic, never-regress safety net. Purely additive: passes,
|
|
19
|
+
* totalLlmCalls, fullRewrites, and the entire section-splice/tie-break/
|
|
20
|
+
* core-rewrite algorithm are completely untouched.
|
|
21
|
+
*/
|
|
22
|
+
export * from "./n-deep.base";
|
|
23
|
+
import { runNDeep as baseRunNDeep, type NDeepOpts, type NDeepResult } from "./n-deep.base";
|
|
24
|
+
import { generateSynthesizedResponse } from "@/lib/models";
|
|
25
|
+
import { detectTruncation } from "./v15-pipeline";
|
|
26
|
+
|
|
27
|
+
const MAX_REPAIR_DRAFT_CHARS = 20_000; // matches the established convention in lib/pipeline.ts's own repair prompts
|
|
28
|
+
|
|
29
|
+
export async function runNDeep(opts: NDeepOpts): Promise<NDeepResult> {
|
|
30
|
+
const result = await baseRunNDeep(opts);
|
|
31
|
+
const trunc = detectTruncation(result.finalText, { longForm: !!opts.fullSloopReport });
|
|
32
|
+
if (!trunc.truncated) return result;
|
|
33
|
+
|
|
34
|
+
opts.onDebug?.(`[N-Deep completion-guard] final draft still truncated after ${result.passes.length} pass(es) (${trunc.reason}) — issuing one bounded completion repair (never regresses; original kept if repair fails)`);
|
|
35
|
+
try {
|
|
36
|
+
const repairPrompt = `The DRAFT below was cut off before completion (${trunc.reason}). Continue writing from EXACTLY where it left off and FINISH it completely — do not restart, do not repeat earlier content, do not summarize what came before. Output the FULL corrected document (original content + your completion), ending on a complete sentence.\n\nUSER ASK: ${opts.userQuery}\n\nDRAFT TO COMPLETE:\n${result.finalText.slice(0, MAX_REPAIR_DRAFT_CHARS)}`;
|
|
37
|
+
const repaired = await generateSynthesizedResponse({
|
|
38
|
+
...opts.baseParams, userMessage: repairPrompt, retrievedWebData: undefined, conversationHistory: [],
|
|
39
|
+
});
|
|
40
|
+
const repairedTrunc = detectTruncation(repaired, { longForm: !!opts.fullSloopReport });
|
|
41
|
+
if (repaired && repaired.trim().length > result.finalText.length && !repairedTrunc.truncated) {
|
|
42
|
+
opts.onDebug?.(`[N-Deep completion-guard] repair accepted (${result.finalText.length} → ${repaired.trim().length} chars, no longer truncated)`);
|
|
43
|
+
return { ...result, finalText: repaired.trim(), totalLlmCalls: result.totalLlmCalls + 1 };
|
|
44
|
+
}
|
|
45
|
+
opts.onDebug?.(`[N-Deep completion-guard] repair rejected (still truncated or not longer) — keeping original draft, never regressing`);
|
|
46
|
+
return result;
|
|
47
|
+
} catch (e) {
|
|
48
|
+
opts.onDebug?.(`[N-Deep completion-guard] repair call failed: ${(e as Error).message} — keeping original draft`);
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
}
|