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,254 @@
|
|
|
1
|
+
import { useEffect, useRef, useState, type RefObject } from "react";
|
|
2
|
+
import {
|
|
3
|
+
getActiveModel,
|
|
4
|
+
getCustomTemplateCount,
|
|
5
|
+
getLastRun,
|
|
6
|
+
getPersonaSeed,
|
|
7
|
+
getSettings,
|
|
8
|
+
observeRuntime,
|
|
9
|
+
type RuntimeSnapshot,
|
|
10
|
+
} from "./engineBridge";
|
|
11
|
+
|
|
12
|
+
type FrameRef = RefObject<HTMLIFrameElement | null>;
|
|
13
|
+
|
|
14
|
+
/* ------------------------------------------------------------------ */
|
|
15
|
+
/* Fiction Input inspector */
|
|
16
|
+
/* ------------------------------------------------------------------ */
|
|
17
|
+
export function FictionInputInspector({ iframeRef }: { iframeRef: FrameRef }) {
|
|
18
|
+
const [tick, setTick] = useState(0);
|
|
19
|
+
const refresh = () => setTick((t) => t + 1);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const id = window.setInterval(refresh, 2500);
|
|
22
|
+
return () => window.clearInterval(id);
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
const frame = iframeRef.current;
|
|
26
|
+
const settings = getSettings(frame);
|
|
27
|
+
const seed = getPersonaSeed(frame);
|
|
28
|
+
const model = getActiveModel(frame);
|
|
29
|
+
const templates = getCustomTemplateCount(frame);
|
|
30
|
+
const lastRun = getLastRun(frame);
|
|
31
|
+
|
|
32
|
+
// Only surface prompt text that the engine ACTUALLY exposed. No fabrication.
|
|
33
|
+
const exposedPrompt =
|
|
34
|
+
lastRun &&
|
|
35
|
+
(typeof lastRun.prompt === "string"
|
|
36
|
+
? (lastRun.prompt as string)
|
|
37
|
+
: typeof lastRun.compiledPrompt === "string"
|
|
38
|
+
? (lastRun.compiledPrompt as string)
|
|
39
|
+
: typeof lastRun.input === "string"
|
|
40
|
+
? (lastRun.input as string)
|
|
41
|
+
: null);
|
|
42
|
+
|
|
43
|
+
const rows: Array<[string, string]> = [
|
|
44
|
+
["Active model", model || "(default)"],
|
|
45
|
+
["Persona seed", seed != null ? String(seed) : "(none)"],
|
|
46
|
+
["Template enabled", String(!!settings.templateEnabled)],
|
|
47
|
+
["Active template", String(settings.activeTemplateId ?? "—")],
|
|
48
|
+
["Style mode", String(settings.styleMode ?? "—")],
|
|
49
|
+
["Deep research", String(!!settings.deepResearch)],
|
|
50
|
+
["Search depth", String(settings.searchDepth ?? "—")],
|
|
51
|
+
["n-Deep passes", settings.nDeepEnabled ? String(settings.nDeepMaxPasses ?? "—") : "off"],
|
|
52
|
+
["Cluster search", settings.clusterSearch ? String(settings.clusterSize ?? "on") : "off"],
|
|
53
|
+
["SLOOP long-form", settings.forceSloop ? String(settings.sloopPages ?? "on") + " pages" : "off"],
|
|
54
|
+
["Custom templates", String(templates)],
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div className="space-y-3 text-[13px]" data-tick={tick}>
|
|
59
|
+
<div className="flex items-center justify-between">
|
|
60
|
+
<p className="text-[12px] text-zinc-600">
|
|
61
|
+
The <b>real parameters</b> the engine uses to compile each chapter prompt (read live from engine storage).
|
|
62
|
+
</p>
|
|
63
|
+
<button onClick={refresh} className="rounded-lg border border-zinc-300 px-2 py-1 text-[11px] hover:bg-zinc-50">
|
|
64
|
+
Refresh
|
|
65
|
+
</button>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div className="grid grid-cols-2 gap-x-3 gap-y-1 rounded-lg border border-zinc-200 bg-white p-3">
|
|
69
|
+
{rows.map(([k, v]) => (
|
|
70
|
+
<div key={k} className="flex items-center justify-between gap-2 border-b border-zinc-50 py-0.5">
|
|
71
|
+
<span className="text-[11px] text-zinc-500">{k}</span>
|
|
72
|
+
<span className="font-mono text-[11px] font-semibold text-zinc-800">{v}</span>
|
|
73
|
+
</div>
|
|
74
|
+
))}
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<div>
|
|
78
|
+
<h4 className="mb-1 text-[12px] font-bold text-zinc-700">Compiled Fiction Input (as exposed by the engine)</h4>
|
|
79
|
+
{exposedPrompt ? (
|
|
80
|
+
<pre className="max-h-64 overflow-auto whitespace-pre-wrap rounded-lg border border-zinc-200 bg-zinc-900 p-2 text-[11px] leading-relaxed text-zinc-100">
|
|
81
|
+
{exposedPrompt}
|
|
82
|
+
</pre>
|
|
83
|
+
) : (
|
|
84
|
+
<p className="rounded-md bg-amber-50 px-2 py-1.5 text-[12px] text-amber-800">
|
|
85
|
+
The current engine build does not export the fully compiled prompt to <code>veritas.lastrun.v1</code>. Enable
|
|
86
|
+
<b> Debug Trace</b> inside the engine (Chat settings) to surface the exact per-chapter prompt; it will appear here
|
|
87
|
+
once written. The parameters above are the honest, verified inputs that drive that prompt.
|
|
88
|
+
</p>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* ------------------------------------------------------------------ */
|
|
96
|
+
/* System map (real module inventory) */
|
|
97
|
+
/* ------------------------------------------------------------------ */
|
|
98
|
+
type Group = { title: string; blurb: string; items: Array<[string, string]> };
|
|
99
|
+
const SYSTEM_MAP: Group[] = [
|
|
100
|
+
{
|
|
101
|
+
title: "SAGA / SAGE core",
|
|
102
|
+
blurb: "Story Archetype Generation Engine — deterministic seeded rolls that fix genre, archetype, and structure.",
|
|
103
|
+
items: [
|
|
104
|
+
["lib/sage/engine.ts", "rollSage() — master seeded roll"],
|
|
105
|
+
["lib/sage/index.ts", "public barrel (taxonomy, prng, judge, saga-os v1-v8)"],
|
|
106
|
+
["lib/sage/saga-os-v2..v8.ts", "successive Saga-OS capability layers"],
|
|
107
|
+
["lib/sage/saga-os-v3-core.ts / -release.ts", "v3 pipeline compile + release rules"],
|
|
108
|
+
["lib/sage/saga-os-v4-aureate.ts", "v4 aureate style/reality layer"],
|
|
109
|
+
["lib/sage/unified-roll.ts", "unifiedRoll() — merges archetype + genre + scale"],
|
|
110
|
+
["lib/sage/taxonomy.ts", "genre/archetype taxonomy tables"],
|
|
111
|
+
["lib/sage/prng.ts", "seeded deterministic PRNG"],
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
title: "Quality & grounding",
|
|
116
|
+
blurb: "Reality-grounding, repetition control, and self-judging feed the chapter prompt and the after-write audit.",
|
|
117
|
+
items: [
|
|
118
|
+
["lib/sage/reality-grounding.ts", "loadRealityLevel() — grounding constraints"],
|
|
119
|
+
["lib/sage/judge.ts", "rubric self-judge"],
|
|
120
|
+
["lib/sage/repetition.ts", "repetition/echo suppression"],
|
|
121
|
+
["lib/sage/empty-space.ts (v6/v7)", "negative-space / what-is-left-unsaid engine"],
|
|
122
|
+
["lib/sage/worked-sketches.ts", "worked scene sketches"],
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
title: "Innovation & persona",
|
|
127
|
+
blurb: "Genome + persona guides shape voice, novelty, and the 'creative tree of life'.",
|
|
128
|
+
items: [
|
|
129
|
+
["lib/innovation-genome-v3..v10.ts", "successive novelty/discovery genomes"],
|
|
130
|
+
["lib/innovation-genome-engine(.v2).ts", "seedToGenome() + diagnostics"],
|
|
131
|
+
["lib/williams-style.ts", "ARCHETYPES + getPersonaDirective()"],
|
|
132
|
+
["lib/williams-persona-guide.ts", "persona guidance tables"],
|
|
133
|
+
["lib/omega-templates.ts", "STYLE_OVERRIDES + authoritative output templates"],
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
title: "Long-form & pipeline",
|
|
138
|
+
blurb: "The runners that turn a blueprint into chapters and multi-pass drafts.",
|
|
139
|
+
items: [
|
|
140
|
+
["lib/longwriter.ts / writing-tiers.ts", "long-form chapter tiering"],
|
|
141
|
+
["lib/v15-pipeline.ts", "runV15OnQuestion / baseline / judge panel"],
|
|
142
|
+
["lib/pipeline.ts", "core generation pipeline"],
|
|
143
|
+
["lib/n-deep.ts", "n-Deep multi-pass convergence"],
|
|
144
|
+
["lib/sloop-runner.ts", "SLOOP paged long-output runner"],
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
title: "Studio UI panels",
|
|
149
|
+
blurb: "The front-end surfaces already wired into the engine (rendered inside the app).",
|
|
150
|
+
items: [
|
|
151
|
+
["components/SagaOsPanel.tsx", "primary Saga-OS studio controls"],
|
|
152
|
+
["components/SageBlueprintPanel.tsx", "blueprint / 'story in one glance'"],
|
|
153
|
+
["components/InnovationPersonaPanel.tsx", "persona genome UI"],
|
|
154
|
+
["components/CreativeTreeOfLifePanel.tsx", "creative tree explorer"],
|
|
155
|
+
["components/CitationLedgerPanel.tsx", "citation ledger"],
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
export function SystemMapPanel() {
|
|
161
|
+
return (
|
|
162
|
+
<div className="space-y-3 text-[13px]">
|
|
163
|
+
<p className="text-[12px] text-zinc-600">
|
|
164
|
+
Capability map of SAGA OS Studio. Module <b>paths are verified</b> against the packaged source
|
|
165
|
+
(<code>node_modules/src</code>); one-line roles are inferred from source structure and marked as such.
|
|
166
|
+
</p>
|
|
167
|
+
<div className="space-y-3">
|
|
168
|
+
{SYSTEM_MAP.map((g) => (
|
|
169
|
+
<div key={g.title} className="rounded-lg border border-zinc-200 bg-white p-3">
|
|
170
|
+
<h4 className="text-[12px] font-bold text-zinc-800">{g.title}</h4>
|
|
171
|
+
<p className="mb-2 text-[11px] text-zinc-500">{g.blurb}</p>
|
|
172
|
+
<div className="space-y-0.5">
|
|
173
|
+
{g.items.map(([path, role]) => (
|
|
174
|
+
<div key={path} className="flex flex-col gap-0.5 border-b border-zinc-50 py-0.5 sm:flex-row sm:items-baseline sm:justify-between">
|
|
175
|
+
<code className="text-[11px] font-semibold text-teal-700">{path}</code>
|
|
176
|
+
<span className="text-[11px] text-zinc-500">{role}</span>
|
|
177
|
+
</div>
|
|
178
|
+
))}
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
))}
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* ------------------------------------------------------------------ */
|
|
188
|
+
/* Live runtime (observed proxy signals) */
|
|
189
|
+
/* ------------------------------------------------------------------ */
|
|
190
|
+
export function RuntimePanel({ iframeRef }: { iframeRef: FrameRef }) {
|
|
191
|
+
const [snap, setSnap] = useState<RuntimeSnapshot | null>(null);
|
|
192
|
+
const [live, setLive] = useState(true);
|
|
193
|
+
const timer = useRef<number | null>(null);
|
|
194
|
+
|
|
195
|
+
useEffect(() => {
|
|
196
|
+
const poll = () => setSnap(observeRuntime(iframeRef.current));
|
|
197
|
+
poll();
|
|
198
|
+
if (live) timer.current = window.setInterval(poll, 1500);
|
|
199
|
+
return () => {
|
|
200
|
+
if (timer.current) window.clearInterval(timer.current);
|
|
201
|
+
};
|
|
202
|
+
}, [live, iframeRef]);
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<div className="space-y-3 text-[13px]">
|
|
206
|
+
<div className="flex items-center justify-between">
|
|
207
|
+
<p className="text-[12px] text-zinc-600">Live runtime of SAGA subsystems in the current story.</p>
|
|
208
|
+
<label className="flex items-center gap-1.5 text-[11px] text-zinc-600">
|
|
209
|
+
<input type="checkbox" checked={live} onChange={(e) => setLive(e.target.checked)} /> live
|
|
210
|
+
</label>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
{snap && (
|
|
214
|
+
<>
|
|
215
|
+
<div className="grid grid-cols-3 gap-2">
|
|
216
|
+
<Stat label="Engine reachable" value={snap.reachable ? "yes" : "no"} />
|
|
217
|
+
<Stat label="Chapters detected" value={String(snap.chapters)} />
|
|
218
|
+
<Stat label="Trace size" value={snap.traceChars.toLocaleString() + " ch"} />
|
|
219
|
+
</div>
|
|
220
|
+
<div className="rounded-lg border border-zinc-200 bg-white p-2">
|
|
221
|
+
<div className="mb-1 text-[11px] font-semibold text-zinc-600">Engine phase: <span className="font-mono">{snap.phase}</span></div>
|
|
222
|
+
<div className="space-y-1">
|
|
223
|
+
{snap.signals.map((s) => (
|
|
224
|
+
<div key={s.label} className="flex items-center gap-2">
|
|
225
|
+
<span className="w-40 shrink-0 text-[11px] text-zinc-600">{s.label}</span>
|
|
226
|
+
<div className="h-2 flex-1 overflow-hidden rounded bg-zinc-100">
|
|
227
|
+
<div
|
|
228
|
+
className={s.count > 0 ? "h-full bg-teal-500" : "h-full bg-zinc-200"}
|
|
229
|
+
style={{ width: Math.min(100, s.count * 8) + "%" }}
|
|
230
|
+
/>
|
|
231
|
+
</div>
|
|
232
|
+
<span className="w-8 text-right font-mono text-[11px] font-semibold text-zinc-700">{s.count}</span>
|
|
233
|
+
</div>
|
|
234
|
+
))}
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
<p className="text-[10px] text-zinc-400">
|
|
238
|
+
Activation counts are a <b>DOM keyword census</b> — an honest proxy observed from the engine's rendered output, not
|
|
239
|
+
source-level instrumentation (which is not accessible in the prebuilt bundle). Chapters = assistant turns detected.
|
|
240
|
+
</p>
|
|
241
|
+
</>
|
|
242
|
+
)}
|
|
243
|
+
</div>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function Stat({ label, value }: { label: string; value: string }) {
|
|
248
|
+
return (
|
|
249
|
+
<div className="rounded-lg border border-zinc-200 bg-white p-2 text-center">
|
|
250
|
+
<div className="font-mono text-sm font-bold text-zinc-800">{value}</div>
|
|
251
|
+
<div className="text-[10px] uppercase tracking-wide text-zinc-400">{label}</div>
|
|
252
|
+
</div>
|
|
253
|
+
);
|
|
254
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { callGeminiResilient, callGemini } from "./gemini";
|
|
3
|
+
import {
|
|
4
|
+
buildGradingPrompt,
|
|
5
|
+
parseGrade,
|
|
6
|
+
buildAsciiReport,
|
|
7
|
+
type GradeReport,
|
|
8
|
+
} from "./grading";
|
|
9
|
+
import { copyText, cx, download } from "./util";
|
|
10
|
+
|
|
11
|
+
type Props = { manuscript: string; apiKey: string; modelPool: string[] };
|
|
12
|
+
|
|
13
|
+
export function ManuscriptGraderPanel({ manuscript, apiKey, modelPool }: Props) {
|
|
14
|
+
const [report, setReport] = useState<GradeReport | null>(null);
|
|
15
|
+
const [busy, setBusy] = useState(false);
|
|
16
|
+
const [err, setErr] = useState<string>("");
|
|
17
|
+
const [modelChoice, setModelChoice] = useState<string>("auto");
|
|
18
|
+
const [log, setLog] = useState<string>("");
|
|
19
|
+
|
|
20
|
+
const canRun = !!manuscript.trim() && !!apiKey.trim() && !busy;
|
|
21
|
+
|
|
22
|
+
async function grade() {
|
|
23
|
+
setBusy(true);
|
|
24
|
+
setErr("");
|
|
25
|
+
setReport(null);
|
|
26
|
+
const { system, prompt } = buildGradingPrompt(manuscript);
|
|
27
|
+
setLog("Grading " + manuscript.length.toLocaleString() + " chars (fresh context)…");
|
|
28
|
+
try {
|
|
29
|
+
const res =
|
|
30
|
+
modelChoice === "auto"
|
|
31
|
+
? await callGeminiResilient(modelPool, undefined, { apiKey, prompt, system, temperature: 0.2 })
|
|
32
|
+
: await callGemini({ apiKey, model: modelChoice, prompt, system, temperature: 0.2 });
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
setErr(res.error || "Grading failed.");
|
|
35
|
+
setLog("Failed on model " + (res.model || "?") + " after " + res.ms + " ms.");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const parsed = parseGrade(res.text, res.model, res.ms);
|
|
39
|
+
setReport(parsed);
|
|
40
|
+
setLog("Graded by " + res.model + " in " + res.ms + " ms." + (parsed.parseError ? " (parse warning)" : ""));
|
|
41
|
+
} finally {
|
|
42
|
+
setBusy(false);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className="space-y-3 text-[13px]">
|
|
48
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
49
|
+
<button
|
|
50
|
+
onClick={grade}
|
|
51
|
+
disabled={!canRun}
|
|
52
|
+
className={cx(
|
|
53
|
+
"rounded-lg px-3 py-1.5 text-[13px] font-semibold text-white",
|
|
54
|
+
canRun ? "bg-teal-600 hover:bg-teal-500" : "bg-zinc-300",
|
|
55
|
+
)}
|
|
56
|
+
>
|
|
57
|
+
{busy ? "Grading…" : "Grade full manuscript"}
|
|
58
|
+
</button>
|
|
59
|
+
<select
|
|
60
|
+
value={modelChoice}
|
|
61
|
+
onChange={(e) => setModelChoice(e.target.value)}
|
|
62
|
+
className="rounded-lg border border-zinc-300 px-2 py-1.5 text-[12px]"
|
|
63
|
+
>
|
|
64
|
+
<option value="auto">Model: random (rotation)</option>
|
|
65
|
+
{modelPool.map((m) => (
|
|
66
|
+
<option key={m} value={m}>
|
|
67
|
+
{m}
|
|
68
|
+
</option>
|
|
69
|
+
))}
|
|
70
|
+
</select>
|
|
71
|
+
{report && (
|
|
72
|
+
<>
|
|
73
|
+
<button
|
|
74
|
+
onClick={() => copyText(buildAsciiReport(report))}
|
|
75
|
+
className="rounded-lg border border-zinc-300 px-2.5 py-1.5 text-[12px] font-medium hover:bg-zinc-50"
|
|
76
|
+
>
|
|
77
|
+
Copy report
|
|
78
|
+
</button>
|
|
79
|
+
<button
|
|
80
|
+
onClick={() => download("manuscript-grade.txt", buildAsciiReport(report))}
|
|
81
|
+
className="rounded-lg border border-zinc-300 px-2.5 py-1.5 text-[12px] font-medium hover:bg-zinc-50"
|
|
82
|
+
>
|
|
83
|
+
Download
|
|
84
|
+
</button>
|
|
85
|
+
</>
|
|
86
|
+
)}
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
{!apiKey.trim() && (
|
|
90
|
+
<p className="rounded-md bg-amber-50 px-2 py-1 text-[12px] text-amber-800">
|
|
91
|
+
No Gemini key detected. Enter one in the engine (Chat → Keys) or in the console header, then reload the manuscript.
|
|
92
|
+
</p>
|
|
93
|
+
)}
|
|
94
|
+
{log && <p className="text-[11px] text-zinc-500">{log}</p>}
|
|
95
|
+
{err && <p className="rounded-md bg-rose-50 px-2 py-1 text-[12px] text-rose-700">{err}</p>}
|
|
96
|
+
|
|
97
|
+
{report && (
|
|
98
|
+
<div className="space-y-4">
|
|
99
|
+
<div className="overflow-x-auto rounded-lg border border-zinc-200">
|
|
100
|
+
<table className="w-full border-collapse text-left text-[12px]">
|
|
101
|
+
<thead className="bg-zinc-100 text-[11px] uppercase tracking-wide text-zinc-600">
|
|
102
|
+
<tr>
|
|
103
|
+
<th className="px-2 py-1.5">Evaluation Criteria (Weight)</th>
|
|
104
|
+
<th className="px-2 py-1.5 text-center">Score</th>
|
|
105
|
+
<th className="px-2 py-1.5 text-center">Weighted</th>
|
|
106
|
+
<th className="px-2 py-1.5 text-center">Grade</th>
|
|
107
|
+
</tr>
|
|
108
|
+
</thead>
|
|
109
|
+
<tbody>
|
|
110
|
+
{report.criteria.map((c) => (
|
|
111
|
+
<tr key={c.key} className="border-t border-zinc-100 align-top">
|
|
112
|
+
<td className="px-2 py-1.5">
|
|
113
|
+
<div className="font-semibold text-zinc-800">
|
|
114
|
+
{c.label} <span className="text-zinc-400">({Math.round(c.weight * 100)}%)</span>
|
|
115
|
+
</div>
|
|
116
|
+
{c.justification && <div className="mt-0.5 text-[11px] text-zinc-500">{c.justification}</div>}
|
|
117
|
+
</td>
|
|
118
|
+
<td className="px-2 py-1.5 text-center font-mono">{c.score}</td>
|
|
119
|
+
<td className="px-2 py-1.5 text-center font-mono">{c.weighted.toFixed(2)}</td>
|
|
120
|
+
<td className="px-2 py-1.5 text-center font-bold">{c.grade}</td>
|
|
121
|
+
</tr>
|
|
122
|
+
))}
|
|
123
|
+
<tr className="border-t-2 border-zinc-300 bg-zinc-50">
|
|
124
|
+
<td className="px-2 py-2 font-bold text-zinc-900">Weighted Composite Score (100%)</td>
|
|
125
|
+
<td className="px-2 py-2 text-center font-mono font-bold">{report.composite.toFixed(2)}</td>
|
|
126
|
+
<td className="px-2 py-2" />
|
|
127
|
+
<td className="px-2 py-2 text-center text-base font-black">{report.compositeGrade}</td>
|
|
128
|
+
</tr>
|
|
129
|
+
</tbody>
|
|
130
|
+
</table>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
{report.narrative && <p className="text-[12px] italic text-zinc-600">{report.narrative}</p>}
|
|
134
|
+
|
|
135
|
+
{report.supplementary.length > 0 && (
|
|
136
|
+
<div>
|
|
137
|
+
<h4 className="mb-1 text-[12px] font-bold text-zinc-700">Supplementary dimensions</h4>
|
|
138
|
+
<div className="flex flex-wrap gap-1.5">
|
|
139
|
+
{report.supplementary.map((s, i) => (
|
|
140
|
+
<span
|
|
141
|
+
key={i}
|
|
142
|
+
title={s.note}
|
|
143
|
+
className="rounded-md border border-zinc-200 bg-white px-2 py-0.5 text-[11px] text-zinc-700"
|
|
144
|
+
>
|
|
145
|
+
{s.label}: <span className="font-mono font-semibold">{s.score}</span>
|
|
146
|
+
</span>
|
|
147
|
+
))}
|
|
148
|
+
</div>
|
|
149
|
+
<p className="mt-1 text-[10px] text-zinc-400">
|
|
150
|
+
Supplementary set uses a standard editorial format (the uploaded criteria image was not available to this build).
|
|
151
|
+
</p>
|
|
152
|
+
</div>
|
|
153
|
+
)}
|
|
154
|
+
|
|
155
|
+
{report.rewrites.length > 0 && (
|
|
156
|
+
<div>
|
|
157
|
+
<h4 className="mb-1 text-[12px] font-bold text-zinc-700">Line-level rewrite suggestions</h4>
|
|
158
|
+
<div className="space-y-2">
|
|
159
|
+
{report.rewrites.map((r, i) => (
|
|
160
|
+
<div key={i} className="rounded-lg border border-zinc-200 bg-white p-2">
|
|
161
|
+
{r.location && <div className="text-[10px] font-semibold uppercase text-zinc-400">{r.location}</div>}
|
|
162
|
+
<div className="text-[12px] text-rose-700">“{r.excerpt}”</div>
|
|
163
|
+
<div className="mt-0.5 text-[11px] text-zinc-500">Diagnosis: {r.diagnosis}</div>
|
|
164
|
+
<div className="mt-0.5 text-[12px] text-emerald-700">→ {r.suggestedRewrite}</div>
|
|
165
|
+
{r.rationale && <div className="mt-0.5 text-[11px] text-zinc-400">Why: {r.rationale}</div>}
|
|
166
|
+
</div>
|
|
167
|
+
))}
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
)}
|
|
171
|
+
|
|
172
|
+
{report.parseError && (
|
|
173
|
+
<details className="rounded-lg border border-zinc-200 bg-zinc-50 p-2">
|
|
174
|
+
<summary className="cursor-pointer text-[12px] font-semibold text-zinc-600">Raw model output</summary>
|
|
175
|
+
<pre className="mt-1 max-h-64 overflow-auto whitespace-pre-wrap text-[11px] text-zinc-600">{report.raw}</pre>
|
|
176
|
+
</details>
|
|
177
|
+
)}
|
|
178
|
+
</div>
|
|
179
|
+
)}
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { useRef, useState } from "react";
|
|
2
|
+
import { callGeminiResilient } from "./gemini";
|
|
3
|
+
import { buildGradingPrompt, buildRevisionPrompt, parseGrade, type GradeReport } from "./grading";
|
|
4
|
+
import { clampNum, copyText, cx, download, nowStamp } from "./util";
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
manuscript: string;
|
|
8
|
+
setManuscript: (s: string) => void;
|
|
9
|
+
apiKey: string;
|
|
10
|
+
modelPool: string[];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type Step = {
|
|
14
|
+
n: number;
|
|
15
|
+
kind: "grade" | "revise";
|
|
16
|
+
model: string;
|
|
17
|
+
composite?: number;
|
|
18
|
+
grade?: string;
|
|
19
|
+
ms: number;
|
|
20
|
+
note?: string;
|
|
21
|
+
ok: boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type Draft = { n: number; text: string; report: GradeReport };
|
|
25
|
+
|
|
26
|
+
export function RecursiveReviserPanel({ manuscript, setManuscript, apiKey, modelPool }: Props) {
|
|
27
|
+
const [target, setTarget] = useState(85);
|
|
28
|
+
const [maxIters, setMaxIters] = useState(4);
|
|
29
|
+
const [running, setRunning] = useState(false);
|
|
30
|
+
const [steps, setSteps] = useState<Step[]>([]);
|
|
31
|
+
const [drafts, setDrafts] = useState<Draft[]>([]);
|
|
32
|
+
const [best, setBest] = useState<Draft | null>(null);
|
|
33
|
+
const [err, setErr] = useState("");
|
|
34
|
+
const abortRef = useRef<AbortController | null>(null);
|
|
35
|
+
|
|
36
|
+
const canRun = !!manuscript.trim() && !!apiKey.trim() && !running;
|
|
37
|
+
|
|
38
|
+
async function gradeText(text: string, excludeModel: string | undefined) {
|
|
39
|
+
const { system, prompt } = buildGradingPrompt(text);
|
|
40
|
+
const res = await callGeminiResilient(modelPool, excludeModel, {
|
|
41
|
+
apiKey,
|
|
42
|
+
prompt,
|
|
43
|
+
system,
|
|
44
|
+
temperature: 0.2,
|
|
45
|
+
signal: abortRef.current?.signal,
|
|
46
|
+
});
|
|
47
|
+
return { res, report: res.ok ? parseGrade(res.text, res.model, res.ms) : null };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function run() {
|
|
51
|
+
setRunning(true);
|
|
52
|
+
setErr("");
|
|
53
|
+
setSteps([]);
|
|
54
|
+
setDrafts([]);
|
|
55
|
+
setBest(null);
|
|
56
|
+
abortRef.current = new AbortController();
|
|
57
|
+
const localSteps: Step[] = [];
|
|
58
|
+
const localDrafts: Draft[] = [];
|
|
59
|
+
const push = (s: Step) => {
|
|
60
|
+
localSteps.push(s);
|
|
61
|
+
setSteps([...localSteps]);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
// Draft 0 baseline grade — fresh context, random model.
|
|
66
|
+
const g0 = await gradeText(manuscript, undefined);
|
|
67
|
+
if (!g0.res.ok || !g0.report) {
|
|
68
|
+
push({ n: 0, kind: "grade", model: g0.res.model, ms: g0.res.ms, ok: false, note: g0.res.error });
|
|
69
|
+
setErr("Baseline grading failed: " + (g0.res.error || "unknown"));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
push({ n: 0, kind: "grade", model: g0.res.model, composite: g0.report.composite, grade: g0.report.compositeGrade, ms: g0.res.ms, ok: true });
|
|
73
|
+
localDrafts.push({ n: 0, text: manuscript, report: g0.report });
|
|
74
|
+
setDrafts([...localDrafts]);
|
|
75
|
+
let current = { text: manuscript, report: g0.report };
|
|
76
|
+
let lastModel = g0.res.model;
|
|
77
|
+
|
|
78
|
+
if (current.report.composite >= target) {
|
|
79
|
+
setBest(localDrafts[0]);
|
|
80
|
+
push({ n: 0, kind: "grade", model: "—", ms: 0, ok: true, note: "Target already met." });
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
for (let i = 1; i <= maxIters; i++) {
|
|
85
|
+
if (abortRef.current?.signal.aborted) break;
|
|
86
|
+
|
|
87
|
+
// Revise — fresh context, random model distinct from last grader.
|
|
88
|
+
const { system: rs, prompt: rp } = buildRevisionPrompt(current.text, current.report, target);
|
|
89
|
+
const rev = await callGeminiResilient(modelPool, lastModel, {
|
|
90
|
+
apiKey,
|
|
91
|
+
prompt: rp,
|
|
92
|
+
system: rs,
|
|
93
|
+
temperature: 0.6,
|
|
94
|
+
signal: abortRef.current?.signal,
|
|
95
|
+
});
|
|
96
|
+
if (!rev.ok || !rev.text.trim()) {
|
|
97
|
+
push({ n: i, kind: "revise", model: rev.model, ms: rev.ms, ok: false, note: rev.error });
|
|
98
|
+
setErr("Revision " + i + " failed: " + (rev.error || "empty output"));
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
const revisedText = rev.text.trim();
|
|
102
|
+
push({ n: i, kind: "revise", model: rev.model, ms: rev.ms, ok: true, note: revisedText.length.toLocaleString() + " chars" });
|
|
103
|
+
lastModel = rev.model;
|
|
104
|
+
|
|
105
|
+
// Grade the new draft — fresh context, random model distinct from reviser.
|
|
106
|
+
const gr = await gradeText(revisedText, rev.model);
|
|
107
|
+
if (!gr.res.ok || !gr.report) {
|
|
108
|
+
push({ n: i, kind: "grade", model: gr.res.model, ms: gr.res.ms, ok: false, note: gr.res.error });
|
|
109
|
+
setErr("Grading of revision " + i + " failed: " + (gr.res.error || "unknown"));
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
push({ n: i, kind: "grade", model: gr.res.model, composite: gr.report.composite, grade: gr.report.compositeGrade, ms: gr.res.ms, ok: true });
|
|
113
|
+
localDrafts.push({ n: i, text: revisedText, report: gr.report });
|
|
114
|
+
setDrafts([...localDrafts]);
|
|
115
|
+
current = { text: revisedText, report: gr.report };
|
|
116
|
+
lastModel = gr.res.model;
|
|
117
|
+
|
|
118
|
+
if (current.report.composite >= target) break;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const bestDraft = localDrafts.slice().sort((a, b) => b.report.composite - a.report.composite)[0] || null;
|
|
122
|
+
setBest(bestDraft);
|
|
123
|
+
} finally {
|
|
124
|
+
setRunning(false);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function stop() {
|
|
129
|
+
abortRef.current?.abort();
|
|
130
|
+
setRunning(false);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const trajectory = drafts.map((d) => d.report.composite);
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<div className="space-y-3 text-[13px]">
|
|
137
|
+
<div className="flex flex-wrap items-end gap-3">
|
|
138
|
+
<label className="text-[12px] font-medium text-zinc-600">
|
|
139
|
+
Target score
|
|
140
|
+
<input
|
|
141
|
+
type="number"
|
|
142
|
+
min={1}
|
|
143
|
+
max={100}
|
|
144
|
+
value={target}
|
|
145
|
+
onChange={(e) => setTarget(clampNum(e.target.value, 1, 100, 85))}
|
|
146
|
+
className="ml-2 w-16 rounded-lg border border-zinc-300 px-2 py-1 text-[12px]"
|
|
147
|
+
/>
|
|
148
|
+
</label>
|
|
149
|
+
<label className="text-[12px] font-medium text-zinc-600">
|
|
150
|
+
Max iterations
|
|
151
|
+
<input
|
|
152
|
+
type="number"
|
|
153
|
+
min={1}
|
|
154
|
+
max={8}
|
|
155
|
+
value={maxIters}
|
|
156
|
+
onChange={(e) => setMaxIters(clampNum(e.target.value, 1, 8, 4))}
|
|
157
|
+
className="ml-2 w-14 rounded-lg border border-zinc-300 px-2 py-1 text-[12px]"
|
|
158
|
+
/>
|
|
159
|
+
</label>
|
|
160
|
+
{!running ? (
|
|
161
|
+
<button
|
|
162
|
+
onClick={run}
|
|
163
|
+
disabled={!canRun}
|
|
164
|
+
className={cx(
|
|
165
|
+
"rounded-lg px-3 py-1.5 text-[13px] font-semibold text-white",
|
|
166
|
+
canRun ? "bg-indigo-600 hover:bg-indigo-500" : "bg-zinc-300",
|
|
167
|
+
)}
|
|
168
|
+
>
|
|
169
|
+
Run recursive revision
|
|
170
|
+
</button>
|
|
171
|
+
) : (
|
|
172
|
+
<button onClick={stop} className="rounded-lg bg-rose-600 px-3 py-1.5 text-[13px] font-semibold text-white hover:bg-rose-500">
|
|
173
|
+
Stop
|
|
174
|
+
</button>
|
|
175
|
+
)}
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<p className="text-[11px] text-zinc-500">
|
|
179
|
+
Each grade and each revision is an independent Gemini call — <b>fresh context, random model</b> (distinct from the previous
|
|
180
|
+
call). The loop stops when the target is met or iterations are exhausted.
|
|
181
|
+
</p>
|
|
182
|
+
|
|
183
|
+
{err && <p className="rounded-md bg-rose-50 px-2 py-1 text-[12px] text-rose-700">{err}</p>}
|
|
184
|
+
|
|
185
|
+
{trajectory.length > 0 && (
|
|
186
|
+
<div className="rounded-lg border border-zinc-200 bg-white p-2">
|
|
187
|
+
<div className="text-[11px] font-semibold text-zinc-600">
|
|
188
|
+
Score trajectory: {trajectory.map((t) => t.toFixed(1)).join(" → ")}{" "}
|
|
189
|
+
{best && <span className="text-emerald-700">(best {best.report.composite.toFixed(2)} {best.report.compositeGrade})</span>}
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
)}
|
|
193
|
+
|
|
194
|
+
{steps.length > 0 && (
|
|
195
|
+
<div className="space-y-1">
|
|
196
|
+
{steps.map((s, i) => (
|
|
197
|
+
<div key={i} className="flex items-center gap-2 rounded-md border border-zinc-100 bg-zinc-50 px-2 py-1 text-[11px]">
|
|
198
|
+
<span className={cx("rounded px-1.5 py-0.5 font-semibold", s.kind === "grade" ? "bg-teal-100 text-teal-800" : "bg-indigo-100 text-indigo-800")}>
|
|
199
|
+
{s.kind === "grade" ? "GRADE" : "REVISE"} #{s.n}
|
|
200
|
+
</span>
|
|
201
|
+
<span className="font-mono text-zinc-500">{s.model || "—"}</span>
|
|
202
|
+
{typeof s.composite === "number" && (
|
|
203
|
+
<span className="font-mono font-semibold text-zinc-800">
|
|
204
|
+
{s.composite.toFixed(2)} ({s.grade})
|
|
205
|
+
</span>
|
|
206
|
+
)}
|
|
207
|
+
<span className="text-zinc-400">{s.ms} ms</span>
|
|
208
|
+
{s.note && <span className={cx("truncate", s.ok ? "text-zinc-500" : "text-rose-600")}>{s.note}</span>}
|
|
209
|
+
</div>
|
|
210
|
+
))}
|
|
211
|
+
</div>
|
|
212
|
+
)}
|
|
213
|
+
|
|
214
|
+
{best && (
|
|
215
|
+
<div className="space-y-2">
|
|
216
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
217
|
+
<h4 className="text-[12px] font-bold text-zinc-700">
|
|
218
|
+
Best draft (#{best.n}) — {best.report.composite.toFixed(2)} {best.report.compositeGrade}
|
|
219
|
+
</h4>
|
|
220
|
+
<button onClick={() => copyText(best.text)} className="rounded-lg border border-zinc-300 px-2.5 py-1 text-[11px] font-medium hover:bg-zinc-50">
|
|
221
|
+
Copy manuscript
|
|
222
|
+
</button>
|
|
223
|
+
<button
|
|
224
|
+
onClick={() => download("revised-manuscript-" + nowStamp().replace(/[: ]/g, "-") + ".txt", best.text)}
|
|
225
|
+
className="rounded-lg border border-zinc-300 px-2.5 py-1 text-[11px] font-medium hover:bg-zinc-50"
|
|
226
|
+
>
|
|
227
|
+
Download
|
|
228
|
+
</button>
|
|
229
|
+
<button
|
|
230
|
+
onClick={() => setManuscript(best.text)}
|
|
231
|
+
className="rounded-lg border border-indigo-300 bg-indigo-50 px-2.5 py-1 text-[11px] font-medium text-indigo-700 hover:bg-indigo-100"
|
|
232
|
+
>
|
|
233
|
+
Use as working manuscript
|
|
234
|
+
</button>
|
|
235
|
+
</div>
|
|
236
|
+
<textarea
|
|
237
|
+
readOnly
|
|
238
|
+
value={best.text}
|
|
239
|
+
className="h-48 w-full resize-y rounded-lg border border-zinc-200 bg-white p-2 font-mono text-[11px] text-zinc-700"
|
|
240
|
+
/>
|
|
241
|
+
</div>
|
|
242
|
+
)}
|
|
243
|
+
</div>
|
|
244
|
+
);
|
|
245
|
+
}
|