@thanh01.pmt/curriculum-kit 1.4.18 → 1.4.21
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/dist/{gateSettings-L3FR2-MO.d.cts → gateSettings-DabOqP6_.d.cts} +94 -1
- package/dist/{gateSettings-L3FR2-MO.d.ts → gateSettings-DabOqP6_.d.ts} +94 -1
- package/dist/index.cjs +872 -186
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +283 -125
- package/dist/index.d.ts +283 -125
- package/dist/index.mjs +865 -188
- package/dist/index.mjs.map +1 -1
- package/dist/storage/index.cjs +21 -9
- package/dist/storage/index.cjs.map +1 -1
- package/dist/storage/index.d.cts +11 -1
- package/dist/storage/index.d.ts +11 -1
- package/dist/storage/index.mjs +21 -10
- package/dist/storage/index.mjs.map +1 -1
- package/dist/workflow/index.cjs +280 -8
- package/dist/workflow/index.cjs.map +1 -1
- package/dist/workflow/index.d.cts +2 -2
- package/dist/workflow/index.d.ts +2 -2
- package/dist/workflow/index.mjs +280 -8
- package/dist/workflow/index.mjs.map +1 -1
- package/package.json +23 -22
- package/LICENSE +0 -21
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
|
4
4
|
import { createOpenAI } from '@ai-sdk/openai';
|
|
5
5
|
import { createDeepSeek } from '@ai-sdk/deepseek';
|
|
6
6
|
import { z } from 'zod';
|
|
7
|
-
import { generateObject, streamObject, streamText } from 'ai';
|
|
7
|
+
import { generateObject, streamObject, streamText, generateText } from 'ai';
|
|
8
8
|
import pRetry from 'p-retry';
|
|
9
9
|
import { jsonrepair } from 'jsonrepair';
|
|
10
10
|
import pLimit from 'p-limit';
|
|
@@ -1501,7 +1501,8 @@ function buildSlideBatchPrompt(params) {
|
|
|
1501
1501
|
skillPrompt,
|
|
1502
1502
|
language = "Vietnamese",
|
|
1503
1503
|
languageDirective = "",
|
|
1504
|
-
headingDirective = ""
|
|
1504
|
+
headingDirective = "",
|
|
1505
|
+
groundContext = ""
|
|
1505
1506
|
} = params;
|
|
1506
1507
|
const slidesSpec = clusterSlides.map((s) => `
|
|
1507
1508
|
- Slide ${s.slideIndex} [Phase: ${s.lessonPhase}] -> Layout: "${s.layoutId}"
|
|
@@ -1514,7 +1515,11 @@ function buildSlideBatchPrompt(params) {
|
|
|
1514
1515
|
const systemPrompt = `
|
|
1515
1516
|
${skillPrompt}
|
|
1516
1517
|
|
|
1517
|
-
|
|
1518
|
+
${groundContext ? `---
|
|
1519
|
+
### PROJECT GROUND CONTEXT (framework, style guide, glossary, canonical knowledge \u2014 author from these):
|
|
1520
|
+
${groundContext}
|
|
1521
|
+
|
|
1522
|
+
---` : ""}
|
|
1518
1523
|
### OPERATIONAL GROUND RULES FOR CHUNK GENERATION:
|
|
1519
1524
|
${languageDirective}
|
|
1520
1525
|
${headingDirective}
|
|
@@ -1585,19 +1590,115 @@ var slideProductionWorkflow_exports = {};
|
|
|
1585
1590
|
__export(slideProductionWorkflow_exports, {
|
|
1586
1591
|
GeneratedSlideArraySchema: () => GeneratedSlideArraySchema,
|
|
1587
1592
|
GeneratedSlideSchema: () => GeneratedSlideSchema,
|
|
1593
|
+
HybridBlueprintArraySchema: () => HybridBlueprintArraySchema,
|
|
1594
|
+
HybridBlueprintItemSchema: () => HybridBlueprintItemSchema,
|
|
1595
|
+
HybridDeckSlideArraySchema: () => HybridDeckSlideArraySchema,
|
|
1596
|
+
HybridDeckSlideSchema: () => HybridDeckSlideSchema,
|
|
1597
|
+
HybridPipelineError: () => HybridPipelineError,
|
|
1588
1598
|
SlideBlueprintArraySchema: () => SlideBlueprintArraySchema,
|
|
1589
1599
|
SlideBlueprintItemSchema: () => SlideBlueprintItemSchema,
|
|
1590
|
-
|
|
1600
|
+
emitUsage: () => emitUsage,
|
|
1601
|
+
executeSlideProductionWorkflow: () => executeSlideProductionWorkflow,
|
|
1602
|
+
extractJsonArray: () => extractJsonArray,
|
|
1603
|
+
validateHybridDeckSlides: () => validateHybridDeckSlides
|
|
1591
1604
|
});
|
|
1605
|
+
function extractJsonArray(raw) {
|
|
1606
|
+
if (!raw) return { error: "empty response" };
|
|
1607
|
+
let text = raw.replace(/<think>[\s\S]*?<\/think>/gi, "").trim();
|
|
1608
|
+
text = text.replace(/^```(?:json)?\s*/m, "").replace(/```\s*$/m, "").trim();
|
|
1609
|
+
const start = text.indexOf("[");
|
|
1610
|
+
const end = text.lastIndexOf("]");
|
|
1611
|
+
if (start < 0 || end <= start) {
|
|
1612
|
+
return {
|
|
1613
|
+
error: "no JSON array span found",
|
|
1614
|
+
head: text.slice(0, 300),
|
|
1615
|
+
tail: text.slice(-300)
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
const span = text.slice(start, end + 1);
|
|
1619
|
+
try {
|
|
1620
|
+
return { value: JSON.parse(span) };
|
|
1621
|
+
} catch {
|
|
1622
|
+
}
|
|
1623
|
+
try {
|
|
1624
|
+
return { value: JSON.parse(jsonrepair(span)) };
|
|
1625
|
+
} catch (e) {
|
|
1626
|
+
return {
|
|
1627
|
+
error: "JSON.parse/jsonrepair failed: " + String(e?.message || e).slice(0, 120),
|
|
1628
|
+
head: text.slice(0, 300),
|
|
1629
|
+
tail: text.slice(-300)
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
function validateHybridDeckSlides(slides, blueprint) {
|
|
1634
|
+
const v = [];
|
|
1635
|
+
if (blueprint.length > 0 && slides.length !== blueprint.length) {
|
|
1636
|
+
v.push(`slide count mismatch: got ${slides.length}, blueprint requires ${blueprint.length}`);
|
|
1637
|
+
}
|
|
1638
|
+
slides.forEach((s, i) => {
|
|
1639
|
+
const n = i + 1;
|
|
1640
|
+
const title = typeof s?.title === "string" ? s.title : "";
|
|
1641
|
+
if (!title.trim()) v.push(`slide ${n}: missing/empty title`);
|
|
1642
|
+
else if (title.length > 150) v.push(`slide ${n}: title too long (${title.length} chars, max 150) \u2014 repetition-loop guard`);
|
|
1643
|
+
const notes = typeof s?.notes === "string" ? s.notes.trim() : "";
|
|
1644
|
+
if (notes.length < 80) v.push(`slide ${n}: presenter notes missing or too short (${notes.length} chars, min 80)`);
|
|
1645
|
+
const code = s?.slots?.code;
|
|
1646
|
+
if (typeof code === "string") {
|
|
1647
|
+
if (code.length > 6e3) v.push(`slide ${n}: code block too long (${code.length} chars, max 6000)`);
|
|
1648
|
+
if (/\/\/\s*TODO|<CODE>|your code here/i.test(code)) v.push(`slide ${n}: placeholder code detected (TODO/<CODE>)`);
|
|
1649
|
+
}
|
|
1650
|
+
});
|
|
1651
|
+
return v.slice(0, 10);
|
|
1652
|
+
}
|
|
1653
|
+
function emitUsage(usage, onProgress) {
|
|
1654
|
+
if (!onProgress || !usage) return;
|
|
1655
|
+
const promptTokens = usage.promptTokens ?? usage.inputTokens ?? 0;
|
|
1656
|
+
const completionTokens = usage.completionTokens ?? usage.outputTokens ?? 0;
|
|
1657
|
+
if (promptTokens === 0 && completionTokens === 0) return;
|
|
1658
|
+
onProgress("@illustrator", JSON.stringify({
|
|
1659
|
+
promptTokens,
|
|
1660
|
+
completionTokens,
|
|
1661
|
+
totalTokens: usage.totalTokens ?? promptTokens + completionTokens,
|
|
1662
|
+
reasoningTokens: usage.reasoningTokens ?? 0
|
|
1663
|
+
}), { type: "usage" });
|
|
1664
|
+
}
|
|
1665
|
+
async function inferTextJson(schema, systemPrompt, userPrompt, options, label) {
|
|
1666
|
+
const model = getAIModel(options.modelOptions);
|
|
1667
|
+
try {
|
|
1668
|
+
const { text, finishReason, usage } = await generateText({
|
|
1669
|
+
model,
|
|
1670
|
+
system: systemPrompt || void 0,
|
|
1671
|
+
prompt: userPrompt,
|
|
1672
|
+
maxOutputTokens: options.maxOutputTokens ?? 65536
|
|
1673
|
+
});
|
|
1674
|
+
emitUsage(usage, options.onProgress);
|
|
1675
|
+
const extracted = extractJsonArray(text);
|
|
1676
|
+
if (!("value" in extracted) || extracted.value === void 0) {
|
|
1677
|
+
console.warn(
|
|
1678
|
+
`[SlideProductionWorkflow] ${label}: JSON extraction failed (${extracted.error}); finish=${finishReason}`,
|
|
1679
|
+
extracted.head ? `head=${String(extracted.head).slice(0, 150)}` : ""
|
|
1680
|
+
);
|
|
1681
|
+
return null;
|
|
1682
|
+
}
|
|
1683
|
+
const validated = schema.safeParse(extracted.value);
|
|
1684
|
+
if (validated.success) return validated.data;
|
|
1685
|
+
console.warn(`[SlideProductionWorkflow] ${label}: output failed schema validation:`, validated.error?.message);
|
|
1686
|
+
return null;
|
|
1687
|
+
} catch (err) {
|
|
1688
|
+
console.warn(`[SlideProductionWorkflow] ${label}: generateText failed:`, err?.message || err);
|
|
1689
|
+
return null;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1592
1692
|
async function inferStructured(schema, systemPrompt, userPrompt, options, label) {
|
|
1593
1693
|
try {
|
|
1594
1694
|
const model = getAIModel(options.modelOptions);
|
|
1595
|
-
const { object } = await generateObject({
|
|
1695
|
+
const { object, usage } = await generateObject({
|
|
1596
1696
|
model,
|
|
1597
1697
|
schema,
|
|
1598
1698
|
system: systemPrompt || void 0,
|
|
1599
1699
|
prompt: userPrompt
|
|
1600
1700
|
});
|
|
1701
|
+
emitUsage(usage, options.onProgress);
|
|
1601
1702
|
const validated = schema.safeParse(object);
|
|
1602
1703
|
if (validated.success) return validated.data;
|
|
1603
1704
|
console.warn(
|
|
@@ -1612,7 +1713,9 @@ async function inferStructured(schema, systemPrompt, userPrompt, options, label)
|
|
|
1612
1713
|
const messages = [
|
|
1613
1714
|
{ role: "user", content: [systemPrompt, userPrompt].filter(Boolean).join("\n\n") }
|
|
1614
1715
|
];
|
|
1615
|
-
const raw = await runCurriculumAIInference(messages, options.satelliteContext || "", options.runnerOptions)
|
|
1716
|
+
const raw = await runCurriculumAIInference(messages, options.satelliteContext || "", options.runnerOptions, (token, type) => {
|
|
1717
|
+
if (type === "usage") options.onProgress?.("@illustrator", token, { type: "usage" });
|
|
1718
|
+
});
|
|
1616
1719
|
const fenceMatch = raw.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
|
|
1617
1720
|
const candidate = (fenceMatch ? fenceMatch[1] : raw).trim();
|
|
1618
1721
|
let parsed;
|
|
@@ -1630,9 +1733,144 @@ async function inferStructured(schema, systemPrompt, userPrompt, options, label)
|
|
|
1630
1733
|
return null;
|
|
1631
1734
|
}
|
|
1632
1735
|
}
|
|
1736
|
+
function normalizeBlueprintItems(items) {
|
|
1737
|
+
return items.sort((a, b) => (a.slideIndex ?? 0) - (b.slideIndex ?? 0)).map((item, idx) => ({
|
|
1738
|
+
slideIndex: idx + 1,
|
|
1739
|
+
clusterId: item.clusterId ?? Math.floor(idx / 5) + 1,
|
|
1740
|
+
clusterTitle: item.clusterTitle || "Cluster",
|
|
1741
|
+
lessonPhase: item.lessonPhase || "Content",
|
|
1742
|
+
layoutId: item.layoutId,
|
|
1743
|
+
title: item.title,
|
|
1744
|
+
pedagogicalGoal: item.pedagogicalGoal || "",
|
|
1745
|
+
contentFocus: item.contentFocus || [],
|
|
1746
|
+
codeSnippetIntent: item.codeSnippetIntent ?? void 0,
|
|
1747
|
+
visualIntent: item.visualIntent ?? void 0
|
|
1748
|
+
}));
|
|
1749
|
+
}
|
|
1750
|
+
function buildHybridDeckPrompts(params) {
|
|
1751
|
+
const { lessonFlow, blueprint, skillPrompt, language, languageDirective, headingDirective, groundContext } = params;
|
|
1752
|
+
const blueprintText = JSON.stringify(
|
|
1753
|
+
blueprint.map((s) => ({
|
|
1754
|
+
slideIndex: s.slideIndex,
|
|
1755
|
+
lessonPhase: s.lessonPhase,
|
|
1756
|
+
layoutId: s.layoutId,
|
|
1757
|
+
title: s.title,
|
|
1758
|
+
pedagogicalGoal: s.pedagogicalGoal,
|
|
1759
|
+
contentFocus: s.contentFocus,
|
|
1760
|
+
codeSnippetIntent: s.codeSnippetIntent ?? void 0,
|
|
1761
|
+
visualIntent: s.visualIntent ?? void 0
|
|
1762
|
+
})),
|
|
1763
|
+
null,
|
|
1764
|
+
1
|
|
1765
|
+
);
|
|
1766
|
+
const phasesContent = lessonFlow.phases.length > 0 ? lessonFlow.phases.map((p) => `### ${p.phaseName}
|
|
1767
|
+
${p.content}`).join("\n\n") : lessonFlow.rawContent;
|
|
1768
|
+
const systemPrompt = [
|
|
1769
|
+
skillPrompt,
|
|
1770
|
+
groundContext || "",
|
|
1771
|
+
languageDirective,
|
|
1772
|
+
headingDirective,
|
|
1773
|
+
`
|
|
1774
|
+
### OPERATIONAL GROUND RULES (FULL-DECK AUTHORING):
|
|
1775
|
+
1. **EXACT COUNT: author EXACTLY ${blueprint.length} slide objects \u2014 ONE per blueprint item, SAME ORDER, SAME layoutId.** Do NOT merge, skip, reorder, or add slides.
|
|
1776
|
+
2. **ZERO ABBREVIATION / NO "// TODO"**: All code snippets MUST be real, fully authored, compilable code relevant to "${lessonFlow.lessonTitle}". Never write placeholders, stubs, or "<CODE>".
|
|
1777
|
+
3. **MANDATORY 3-PART PRESENTER NOTES ON EVERY SLIDE (120+ chars)**: SCRIPT (60-90s spoken talk track with an intuitive analogy), COLD CALL / CHECK (one targeted understanding question), SCAFFOLDING / GOTCHA (one common misconception or bug).
|
|
1778
|
+
4. Titles must be < 100 characters \u2014 never repeat or loop text.
|
|
1779
|
+
5. Output ONLY the JSON array. No prose, no markdown fences.
|
|
1780
|
+
`.trim()
|
|
1781
|
+
].filter(Boolean).join("\n\n");
|
|
1782
|
+
const userPrompt = `
|
|
1783
|
+
### BLUEPRINT (${blueprint.length} slides \u2014 AUTHOR ALL OF THEM, in this exact order):
|
|
1784
|
+
${blueprintText}
|
|
1785
|
+
|
|
1786
|
+
### LESSON GROUND TRUTH:
|
|
1787
|
+
- Lesson Title: "${lessonFlow.lessonTitle}"
|
|
1788
|
+
- Target Duration: ${lessonFlow.estimatedDuration}
|
|
1789
|
+
- Pedagogy: "${lessonFlow.pedagogicalModel.toUpperCase()}"
|
|
1790
|
+
- Language: "${language}"
|
|
1791
|
+
|
|
1792
|
+
### LESSON PHASE CONTENT (SOURCE OF TRUTH FOR REAL CONTENT):
|
|
1793
|
+
${phasesContent.slice(0, 16e3)}
|
|
1794
|
+
|
|
1795
|
+
---
|
|
1796
|
+
|
|
1797
|
+
### OUTPUT:
|
|
1798
|
+
A single JSON array of exactly ${blueprint.length} slide objects:
|
|
1799
|
+
\`\`\`json
|
|
1800
|
+
[
|
|
1801
|
+
{
|
|
1802
|
+
"id": "slide-1",
|
|
1803
|
+
"layoutId": "${blueprint[0]?.layoutId || "split-concept-code"}",
|
|
1804
|
+
"title": "${blueprint[0]?.title || "Slide Title"}",
|
|
1805
|
+
"slots": { "...layout-specific slots with REAL content..." },
|
|
1806
|
+
"notes": "SCRIPT: ...\\nCOLD CALL: ...\\nSCAFFOLDING: ..."
|
|
1807
|
+
}
|
|
1808
|
+
]
|
|
1809
|
+
\`\`\`
|
|
1810
|
+
`.trim();
|
|
1811
|
+
return { systemPrompt, userPrompt };
|
|
1812
|
+
}
|
|
1813
|
+
async function runHybridPipeline(ctx) {
|
|
1814
|
+
const { lessonFlow, blueprintPrompt, skillPrompt, language, languageDirective, headingDirective, maxRetries, options, onProgress } = ctx;
|
|
1815
|
+
let blueprint = null;
|
|
1816
|
+
for (let attempt = 1; attempt <= maxRetries && !blueprint; attempt++) {
|
|
1817
|
+
onProgress?.("@illustrator", `[1/4] L\u1EADp D\xE0n \xFD Slides \u2014 hybrid blueprint (l\u1EA7n ${attempt}/${maxRetries})...`);
|
|
1818
|
+
const parsed = await inferTextJson(HybridBlueprintArraySchema, "", blueprintPrompt, options, `hybrid-blueprint#${attempt}`);
|
|
1819
|
+
if (parsed && parsed.length > 0) {
|
|
1820
|
+
blueprint = normalizeBlueprintItems(parsed);
|
|
1821
|
+
} else if (attempt < maxRetries) {
|
|
1822
|
+
onProgress?.("@illustrator", `\u26A0\uFE0F Hybrid blueprint l\u1EA7n ${attempt}/${maxRetries} l\u1ED7i \u2014 th\u1EED l\u1EA1i...`, { type: "warning" });
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
if (!blueprint || blueprint.length === 0) {
|
|
1826
|
+
throw new HybridPipelineError(`blueprint failed after ${maxRetries} attempts`);
|
|
1827
|
+
}
|
|
1828
|
+
onProgress?.("@illustrator", `[1/4] D\xE0n \xFD ${blueprint.length} slides ho\xE0n t\u1EA5t \u2014 chuy\u1EC3n sang authoring to\xE0n deck...`);
|
|
1829
|
+
const { systemPrompt, userPrompt } = buildHybridDeckPrompts({
|
|
1830
|
+
lessonFlow,
|
|
1831
|
+
blueprint,
|
|
1832
|
+
skillPrompt,
|
|
1833
|
+
language,
|
|
1834
|
+
languageDirective,
|
|
1835
|
+
headingDirective,
|
|
1836
|
+
groundContext: options.groundContext
|
|
1837
|
+
});
|
|
1838
|
+
let slides = null;
|
|
1839
|
+
let lastViolations = [];
|
|
1840
|
+
for (let attempt = 1; attempt <= maxRetries && !slides; attempt++) {
|
|
1841
|
+
onProgress?.("@illustrator", `[2/4] Sinh chi ti\u1EBFt to\xE0n b\u1ED9 ${blueprint.length} slides trong 1 l\u1EA7n g\u1ECDi (l\u1EA7n ${attempt}/${maxRetries})...`);
|
|
1842
|
+
const feedback = attempt > 1 && lastViolations.length > 0 ? `
|
|
1843
|
+
|
|
1844
|
+
### \u26A0\uFE0F PREVIOUS ATTEMPT REJECTED \u2014 fix these violations:
|
|
1845
|
+
${lastViolations.map((x) => "- " + x).join("\n")}
|
|
1846
|
+
Return exactly ${blueprint.length} slides, same order as the blueprint.` : "";
|
|
1847
|
+
const parsed = await inferTextJson(HybridDeckSlideArraySchema, systemPrompt, userPrompt + feedback, options, `hybrid-author#${attempt}`);
|
|
1848
|
+
if (!parsed || parsed.length === 0) {
|
|
1849
|
+
lastViolations = ["Output missing, empty, or not a valid JSON array of slide objects"];
|
|
1850
|
+
} else {
|
|
1851
|
+
const violations = validateHybridDeckSlides(parsed, blueprint);
|
|
1852
|
+
if (violations.length === 0) {
|
|
1853
|
+
slides = parsed;
|
|
1854
|
+
break;
|
|
1855
|
+
}
|
|
1856
|
+
lastViolations = violations;
|
|
1857
|
+
}
|
|
1858
|
+
if (attempt < maxRetries) {
|
|
1859
|
+
onProgress?.("@illustrator", `\u26A0\uFE0F Deck authoring l\u1EA7n ${attempt}/${maxRetries} vi ph\u1EA1m guardrails \u2014 retry v\u1EDBi corrective feedback...`, {
|
|
1860
|
+
type: "warning",
|
|
1861
|
+
violations: lastViolations
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
if (!slides) {
|
|
1866
|
+
throw new HybridPipelineError(
|
|
1867
|
+
`deck authoring failed after ${maxRetries} attempts. Last violations: ${lastViolations.slice(0, 3).join("; ")}`
|
|
1868
|
+
);
|
|
1869
|
+
}
|
|
1870
|
+
return { slides, blueprint };
|
|
1871
|
+
}
|
|
1633
1872
|
async function executeSlideProductionWorkflow(options) {
|
|
1634
1873
|
const {
|
|
1635
|
-
lessonMarkdown,
|
|
1636
1874
|
lessonCode,
|
|
1637
1875
|
lessonTitle,
|
|
1638
1876
|
targetSlideCount,
|
|
@@ -1643,6 +1881,7 @@ async function executeSlideProductionWorkflow(options) {
|
|
|
1643
1881
|
maxRetries = 3,
|
|
1644
1882
|
onProgress
|
|
1645
1883
|
} = options;
|
|
1884
|
+
const engineRequested = options.engine ?? "hybrid";
|
|
1646
1885
|
let presentationKitSkills = null;
|
|
1647
1886
|
let presentationKitCore = null;
|
|
1648
1887
|
try {
|
|
@@ -1653,117 +1892,141 @@ async function executeSlideProductionWorkflow(options) {
|
|
|
1653
1892
|
presentationKitCore = await import('@thanh01.pmt/presentation-kit');
|
|
1654
1893
|
} catch {
|
|
1655
1894
|
}
|
|
1656
|
-
const
|
|
1657
|
-
onProgress?.("@illustrator", `[1/4] Ph\xE2n t\xEDch m\u1EA1ch b\xE0i gi\u1EA3ng LESSON & L\u1EADp D\xE0n \xFD ${countLabel}Slides...`);
|
|
1658
|
-
const lessonFlow = parseLessonFlow(lessonMarkdown);
|
|
1895
|
+
const lessonFlow = parseLessonFlow(options.lessonMarkdown);
|
|
1659
1896
|
const getStylePreset = presentationKitSkills?.getStylePreset;
|
|
1660
1897
|
const stylePreset = getStylePreset ? getStylePreset(stylePresetId) : { name: "Blue Professional" };
|
|
1898
|
+
const skillPrompt = presentationKitSkills?.getFrontendSlidesSkillPrompt ? presentationKitSkills.getFrontendSlidesSkillPrompt({ stylePresetId }) : "";
|
|
1661
1899
|
const blueprintPrompt = buildSlideBlueprintPrompt({
|
|
1662
1900
|
lessonFlow,
|
|
1663
1901
|
targetSlideCount,
|
|
1664
1902
|
stylePresetName: stylePreset?.name || "Blue Professional"
|
|
1665
1903
|
});
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1904
|
+
let blueprintItems;
|
|
1905
|
+
let allGeneratedSlides;
|
|
1906
|
+
let engineUsed = engineRequested;
|
|
1907
|
+
const hybridResult = engineRequested === "hybrid" ? await runHybridPipeline({
|
|
1908
|
+
lessonFlow,
|
|
1909
|
+
blueprintPrompt,
|
|
1910
|
+
skillPrompt,
|
|
1911
|
+
language,
|
|
1912
|
+
languageDirective,
|
|
1913
|
+
headingDirective,
|
|
1914
|
+
maxRetries,
|
|
1915
|
+
options,
|
|
1916
|
+
onProgress
|
|
1917
|
+
}).catch((hybridErr) => {
|
|
1918
|
+
console.warn(`[SlideProductionWorkflow] Hybrid engine failed: ${hybridErr?.message || hybridErr} \u2014 falling back to chunked pipeline.`);
|
|
1919
|
+
onProgress?.("@illustrator", `\u26A0\uFE0F Hybrid engine l\u1ED7i \u2014 chuy\u1EC3n sang chunked pipeline (per-cluster)...`, { type: "warning" });
|
|
1920
|
+
return null;
|
|
1921
|
+
}) : null;
|
|
1922
|
+
if (hybridResult) {
|
|
1923
|
+
blueprintItems = hybridResult.blueprint;
|
|
1924
|
+
allGeneratedSlides = hybridResult.slides.map((s, idx) => ({
|
|
1925
|
+
id: s.id || `slide-${idx + 1}`,
|
|
1926
|
+
layoutId: s.layoutId,
|
|
1927
|
+
title: s.title,
|
|
1928
|
+
slots: s.slots || {},
|
|
1929
|
+
notes: s.notes || ""
|
|
1930
|
+
}));
|
|
1931
|
+
} else {
|
|
1932
|
+
engineUsed = "chunked";
|
|
1933
|
+
const countLabel = targetSlideCount ? `${targetSlideCount} ` : "h\u1EEFu c\u01A1 ";
|
|
1934
|
+
onProgress?.("@illustrator", `[1/4] Ph\xE2n t\xEDch m\u1EA1ch b\xE0i gi\u1EA3ng LESSON & L\u1EADp D\xE0n \xFD ${countLabel}Slides...`);
|
|
1935
|
+
blueprintItems = await pRetry(
|
|
1936
|
+
async () => {
|
|
1937
|
+
const items = await inferStructured(
|
|
1938
|
+
SlideBlueprintArraySchema,
|
|
1939
|
+
"",
|
|
1940
|
+
blueprintPrompt,
|
|
1941
|
+
options,
|
|
1942
|
+
"blueprint"
|
|
1943
|
+
);
|
|
1944
|
+
if (!items || items.length === 0) {
|
|
1945
|
+
throw new Error("Blueprint generation returned empty or schema-invalid output");
|
|
1946
|
+
}
|
|
1947
|
+
return normalizeBlueprintItems(items);
|
|
1948
|
+
},
|
|
1949
|
+
{
|
|
1950
|
+
retries: maxRetries - 1,
|
|
1951
|
+
onFailedAttempt: (err) => {
|
|
1952
|
+
onProgress?.("@illustrator", `\u26A0\uFE0F Blueprint attempt ${err.attemptNumber}/${maxRetries} failed \u2014 retrying...`, {
|
|
1953
|
+
type: "warning"
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1694
1956
|
}
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
const matchingPhases = lessonFlow.phases.filter((p) => clusterPhaseNames.has(p.phaseName.toLowerCase()));
|
|
1714
|
-
const lessonExcerpt = matchingPhases.length > 0 ? matchingPhases.map((p) => `### ${p.phaseName}
|
|
1957
|
+
);
|
|
1958
|
+
const clustersMap = /* @__PURE__ */ new Map();
|
|
1959
|
+
for (const item of blueprintItems) {
|
|
1960
|
+
const cId = item.clusterId || Math.floor((item.slideIndex - 1) / 5) + 1;
|
|
1961
|
+
if (!clustersMap.has(cId)) clustersMap.set(cId, []);
|
|
1962
|
+
clustersMap.get(cId).push(item);
|
|
1963
|
+
}
|
|
1964
|
+
const clusters = Array.from(clustersMap.entries()).sort(([a], [b]) => a - b);
|
|
1965
|
+
allGeneratedSlides = [];
|
|
1966
|
+
const failedClusters = [];
|
|
1967
|
+
let clusterIdx = 0;
|
|
1968
|
+
for (const [cId, clusterSlides] of clusters) {
|
|
1969
|
+
clusterIdx++;
|
|
1970
|
+
const clusterTitle = clusterSlides[0]?.clusterTitle || `Giai \u0111o\u1EA1n ${clusterIdx}`;
|
|
1971
|
+
onProgress?.("@illustrator", `[2/4] Sinh chi ti\u1EBFt C\u1EE5m ${clusterIdx}/${clusters.length}: "${clusterTitle}" (${clusterSlides.length} slides)...`);
|
|
1972
|
+
const clusterPhaseNames = new Set(clusterSlides.map((s) => s.lessonPhase.toLowerCase()));
|
|
1973
|
+
const matchingPhases = lessonFlow.phases.filter((p) => clusterPhaseNames.has(p.phaseName.toLowerCase()));
|
|
1974
|
+
const lessonExcerpt = matchingPhases.length > 0 ? matchingPhases.map((p) => `### ${p.phaseName}
|
|
1715
1975
|
${p.content}`).join("\n\n") : lessonFlow.rawContent.slice(0, 3500);
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1976
|
+
const { systemPrompt, userPrompt } = buildSlideBatchPrompt({
|
|
1977
|
+
clusterId: cId,
|
|
1978
|
+
clusterTitle,
|
|
1979
|
+
clusterSlides,
|
|
1980
|
+
lessonFlow,
|
|
1981
|
+
lessonExcerpt,
|
|
1982
|
+
skillPrompt,
|
|
1983
|
+
language,
|
|
1984
|
+
languageDirective,
|
|
1985
|
+
headingDirective,
|
|
1986
|
+
groundContext: options.groundContext
|
|
1987
|
+
});
|
|
1988
|
+
try {
|
|
1989
|
+
const batchSlides = await pRetry(
|
|
1990
|
+
async () => {
|
|
1991
|
+
const slides = await inferStructured(
|
|
1992
|
+
GeneratedSlideArraySchema,
|
|
1993
|
+
systemPrompt,
|
|
1994
|
+
userPrompt,
|
|
1995
|
+
options,
|
|
1996
|
+
`cluster-${cId}`
|
|
1997
|
+
);
|
|
1998
|
+
if (!slides || slides.length === 0) {
|
|
1999
|
+
throw new Error(`Cluster ${cId} returned empty or schema-invalid output`);
|
|
2000
|
+
}
|
|
2001
|
+
return slides;
|
|
2002
|
+
},
|
|
2003
|
+
{
|
|
2004
|
+
retries: maxRetries - 1,
|
|
2005
|
+
onFailedAttempt: (err) => {
|
|
2006
|
+
onProgress?.("@illustrator", `\u26A0\uFE0F C\u1EE5m ${clusterIdx} l\u1EA7n ${err.attemptNumber}/${maxRetries} l\u1ED7i \u2014 retry ri\xEAng c\u1EE5m n\xE0y...`, {
|
|
2007
|
+
type: "warning"
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
1748
2010
|
}
|
|
1749
|
-
|
|
2011
|
+
);
|
|
2012
|
+
allGeneratedSlides.push(...batchSlides);
|
|
2013
|
+
} catch (clusterErr) {
|
|
2014
|
+
failedClusters.push(cId);
|
|
2015
|
+
console.error(`[SlideProductionWorkflow] Cluster ${cId} permanently failed after ${maxRetries} attempts:`, clusterErr?.message || clusterErr);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
if (failedClusters.length > 0) {
|
|
2019
|
+
throw new Error(
|
|
2020
|
+
`[SlideProductionWorkflow] Failed to generate ${failedClusters.length}/${clusters.length} cluster(s) (clusterId: ${failedClusters.join(", ")}) after ${maxRetries} attempts each. Aborting to prevent placeholder/degraded slide output. Review provider keys/model availability and retry.`
|
|
1750
2021
|
);
|
|
1751
|
-
allGeneratedSlides.push(...batchSlides);
|
|
1752
|
-
} catch (clusterErr) {
|
|
1753
|
-
failedClusters.push(cId);
|
|
1754
|
-
console.error(`[SlideProductionWorkflow] Cluster ${cId} permanently failed after ${maxRetries} attempts:`, clusterErr?.message || clusterErr);
|
|
1755
2022
|
}
|
|
1756
2023
|
}
|
|
1757
|
-
if (failedClusters.length > 0) {
|
|
1758
|
-
throw new Error(
|
|
1759
|
-
`[SlideProductionWorkflow] Failed to generate ${failedClusters.length}/${clusters.length} cluster(s) (clusterId: ${failedClusters.join(", ")}) after ${maxRetries} attempts each. Aborting to prevent placeholder/degraded slide output. Review provider keys/model availability and retry.`
|
|
1760
|
-
);
|
|
1761
|
-
}
|
|
1762
2024
|
onProgress?.("@illustrator", `[3/4] Chu\u1EA9n h\xF3a b\u1ED1 c\u1EE5c v\xE0 bi\xEAn d\u1ECBch 1920\xD71080 Stage Deck (${allGeneratedSlides.length} slides)...`);
|
|
1763
2025
|
const normalizer = presentationKitCore?.normalizeSlideSlots;
|
|
1764
2026
|
const normalizedSlides = allGeneratedSlides.map((s, idx) => {
|
|
1765
2027
|
const base = normalizer ? normalizer(s) : s;
|
|
1766
2028
|
if (!base.id) base.id = `slide-${idx + 1}`;
|
|
2029
|
+
if (!base.slots || typeof base.slots !== "object") base.slots = {};
|
|
1767
2030
|
return base;
|
|
1768
2031
|
});
|
|
1769
2032
|
const deckJson = {
|
|
@@ -1773,16 +2036,19 @@ ${p.content}`).join("\n\n") : lessonFlow.rawContent.slice(0, 3500);
|
|
|
1773
2036
|
slides: normalizedSlides
|
|
1774
2037
|
};
|
|
1775
2038
|
let compiledHtml;
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
} catch (compErr) {
|
|
1784
|
-
console.warn(`[SlideProductionWorkflow] Failed compiling HTML deck:`, compErr?.message || compErr);
|
|
2039
|
+
try {
|
|
2040
|
+
let compiled = null;
|
|
2041
|
+
if (typeof presentationKitCore?.compileHtmlDeckAsync === "function") {
|
|
2042
|
+
compiled = await presentationKitCore.compileHtmlDeckAsync(deckJson);
|
|
2043
|
+
}
|
|
2044
|
+
if (!compiled?.html && typeof presentationKitCore?.compileHtmlDeck === "function") {
|
|
2045
|
+
compiled = presentationKitCore.compileHtmlDeck(deckJson);
|
|
1785
2046
|
}
|
|
2047
|
+
if (compiled?.html) {
|
|
2048
|
+
compiledHtml = compiled.html;
|
|
2049
|
+
}
|
|
2050
|
+
} catch (compErr) {
|
|
2051
|
+
console.warn(`[SlideProductionWorkflow] Failed compiling HTML deck:`, compErr?.message || compErr);
|
|
1786
2052
|
}
|
|
1787
2053
|
const markdownWrapper = `---
|
|
1788
2054
|
id: "SLIDE_${lessonCode}"
|
|
@@ -1806,10 +2072,11 @@ ${JSON.stringify(deckJson, null, 2)}
|
|
|
1806
2072
|
compiledHtml,
|
|
1807
2073
|
markdownWrapper,
|
|
1808
2074
|
blueprint: blueprintItems,
|
|
1809
|
-
slideCount: normalizedSlides.length
|
|
2075
|
+
slideCount: normalizedSlides.length,
|
|
2076
|
+
engine: engineUsed
|
|
1810
2077
|
};
|
|
1811
2078
|
}
|
|
1812
|
-
var SlideBlueprintItemSchema, SlideBlueprintArraySchema, GeneratedSlideSchema, GeneratedSlideArraySchema;
|
|
2079
|
+
var LAYOUT_ID_ENUM, SlideBlueprintItemSchema, SlideBlueprintArraySchema, GeneratedSlideSchema, GeneratedSlideArraySchema, HybridBlueprintItemSchema, HybridBlueprintArraySchema, HybridDeckSlideSchema, HybridDeckSlideArraySchema, HybridPipelineError;
|
|
1813
2080
|
var init_slideProductionWorkflow = __esm({
|
|
1814
2081
|
"src/services/slideProductionWorkflow.ts"() {
|
|
1815
2082
|
init_lessonFlowParser();
|
|
@@ -1817,37 +2084,61 @@ var init_slideProductionWorkflow = __esm({
|
|
|
1817
2084
|
init_slideBatchPrompt();
|
|
1818
2085
|
init_provider_factory();
|
|
1819
2086
|
init_streamRunner();
|
|
2087
|
+
LAYOUT_ID_ENUM = z.enum([
|
|
2088
|
+
"hero-cover",
|
|
2089
|
+
"split-concept-code",
|
|
2090
|
+
"two-columns-compare",
|
|
2091
|
+
"three-cards-grid",
|
|
2092
|
+
"timeline-steps",
|
|
2093
|
+
"metric-callout",
|
|
2094
|
+
"checkpoint-quiz",
|
|
2095
|
+
"tiered-practice-3cards",
|
|
2096
|
+
"summary-takeaways"
|
|
2097
|
+
]);
|
|
1820
2098
|
SlideBlueprintItemSchema = z.object({
|
|
1821
2099
|
slideIndex: z.number().int().min(1),
|
|
1822
|
-
clusterId: z.number().int().min(1).default(1),
|
|
1823
|
-
clusterTitle: z.string().default("Cluster"),
|
|
1824
|
-
lessonPhase: z.string().default("Content"),
|
|
1825
|
-
layoutId:
|
|
1826
|
-
"hero-cover",
|
|
1827
|
-
"split-concept-code",
|
|
1828
|
-
"two-columns-compare",
|
|
1829
|
-
"three-cards-grid",
|
|
1830
|
-
"timeline-steps",
|
|
1831
|
-
"metric-callout",
|
|
1832
|
-
"checkpoint-quiz",
|
|
1833
|
-
"tiered-practice-3cards",
|
|
1834
|
-
"summary-takeaways"
|
|
1835
|
-
]),
|
|
2100
|
+
clusterId: z.number().int().min(1).nullish().default(1),
|
|
2101
|
+
clusterTitle: z.string().nullish().default("Cluster"),
|
|
2102
|
+
lessonPhase: z.string().nullish().default("Content"),
|
|
2103
|
+
layoutId: LAYOUT_ID_ENUM,
|
|
1836
2104
|
title: z.string().min(1),
|
|
1837
|
-
pedagogicalGoal: z.string().default(""),
|
|
1838
|
-
contentFocus: z.array(z.string()).default([]),
|
|
1839
|
-
codeSnippetIntent: z.string().
|
|
1840
|
-
visualIntent: z.string().
|
|
2105
|
+
pedagogicalGoal: z.string().nullish().default(""),
|
|
2106
|
+
contentFocus: z.array(z.string()).nullish().default([]),
|
|
2107
|
+
codeSnippetIntent: z.string().nullish(),
|
|
2108
|
+
visualIntent: z.string().nullish()
|
|
1841
2109
|
});
|
|
1842
2110
|
SlideBlueprintArraySchema = z.array(SlideBlueprintItemSchema);
|
|
1843
2111
|
GeneratedSlideSchema = z.object({
|
|
1844
|
-
id: z.string().
|
|
1845
|
-
layoutId: z.string(),
|
|
2112
|
+
id: z.string().nullish(),
|
|
2113
|
+
layoutId: z.string().min(1),
|
|
1846
2114
|
title: z.string().min(1),
|
|
1847
|
-
slots: z.record(z.any()).default({}),
|
|
1848
|
-
notes: z.string().default("")
|
|
2115
|
+
slots: z.record(z.any()).nullish().default({}),
|
|
2116
|
+
notes: z.string().nullish().default("")
|
|
1849
2117
|
});
|
|
1850
2118
|
GeneratedSlideArraySchema = z.array(GeneratedSlideSchema);
|
|
2119
|
+
HybridBlueprintItemSchema = z.object({
|
|
2120
|
+
slideIndex: z.number().int().min(1),
|
|
2121
|
+
clusterId: z.number().int().min(1).nullish(),
|
|
2122
|
+
clusterTitle: z.string().nullish(),
|
|
2123
|
+
lessonPhase: z.string().nullish(),
|
|
2124
|
+
layoutId: LAYOUT_ID_ENUM,
|
|
2125
|
+
title: z.string().min(1).max(300),
|
|
2126
|
+
pedagogicalGoal: z.string().nullish().default(""),
|
|
2127
|
+
contentFocus: z.array(z.string()).nullish().default([]),
|
|
2128
|
+
codeSnippetIntent: z.string().nullish(),
|
|
2129
|
+
visualIntent: z.string().nullish()
|
|
2130
|
+
});
|
|
2131
|
+
HybridBlueprintArraySchema = z.array(HybridBlueprintItemSchema);
|
|
2132
|
+
HybridDeckSlideSchema = z.object({
|
|
2133
|
+
id: z.string().nullish(),
|
|
2134
|
+
layoutId: z.string().min(1),
|
|
2135
|
+
title: z.string().min(1).max(300),
|
|
2136
|
+
slots: z.record(z.any()).nullish().default({}),
|
|
2137
|
+
notes: z.string().nullish().default("")
|
|
2138
|
+
});
|
|
2139
|
+
HybridDeckSlideArraySchema = z.array(HybridDeckSlideSchema);
|
|
2140
|
+
HybridPipelineError = class extends Error {
|
|
2141
|
+
};
|
|
1851
2142
|
}
|
|
1852
2143
|
});
|
|
1853
2144
|
var LearningObjectiveRowSchema = z.object({
|
|
@@ -9034,6 +9325,21 @@ var STANDARD_SOT_FILES = [
|
|
|
9034
9325
|
"ART_DIRECTION.md",
|
|
9035
9326
|
"ALIGNMENT_MATRIX.md"
|
|
9036
9327
|
];
|
|
9328
|
+
function atomicWriteFileSync(targetPath, content) {
|
|
9329
|
+
const dir = path3.dirname(targetPath);
|
|
9330
|
+
if (!fs2.existsSync(dir)) fs2.mkdirSync(dir, { recursive: true });
|
|
9331
|
+
const tmpPath = path3.join(dir, `.${path3.basename(targetPath)}.${process.pid}.${Date.now()}.${crypto.randomBytes(4).toString("hex")}.tmp`);
|
|
9332
|
+
try {
|
|
9333
|
+
fs2.writeFileSync(tmpPath, content, "utf-8");
|
|
9334
|
+
fs2.renameSync(tmpPath, targetPath);
|
|
9335
|
+
} catch (err) {
|
|
9336
|
+
try {
|
|
9337
|
+
if (fs2.existsSync(tmpPath)) fs2.unlinkSync(tmpPath);
|
|
9338
|
+
} catch {
|
|
9339
|
+
}
|
|
9340
|
+
throw err;
|
|
9341
|
+
}
|
|
9342
|
+
}
|
|
9037
9343
|
var FileSystemCurriculumAdapter = class {
|
|
9038
9344
|
baseDir;
|
|
9039
9345
|
constructor(options = {}) {
|
|
@@ -9172,7 +9478,7 @@ var FileSystemCurriculumAdapter = class {
|
|
|
9172
9478
|
if (oldContent !== content) {
|
|
9173
9479
|
const historyDir = path3.join(projectDir, ".history", relPath);
|
|
9174
9480
|
fs2.mkdirSync(historyDir, { recursive: true });
|
|
9175
|
-
|
|
9481
|
+
atomicWriteFileSync(path3.join(historyDir, `${Date.now()}.md`), oldContent);
|
|
9176
9482
|
const versions = fs2.readdirSync(historyDir).filter((f) => f.endsWith(".md")).sort();
|
|
9177
9483
|
while (versions.length > 10) {
|
|
9178
9484
|
fs2.unlinkSync(path3.join(historyDir, versions.shift()));
|
|
@@ -9182,19 +9488,15 @@ var FileSystemCurriculumAdapter = class {
|
|
|
9182
9488
|
console.warn("[FileSystemCurriculumAdapter] version history snapshot failed:", histErr?.message || histErr);
|
|
9183
9489
|
}
|
|
9184
9490
|
}
|
|
9185
|
-
|
|
9491
|
+
atomicWriteFileSync(targetPath, content);
|
|
9186
9492
|
const filename = path3.basename(relPath);
|
|
9187
9493
|
const match = filename.match(/(LESSON|ACT|QUIZ|SLIDE|GUIDE|HANDOUT|WKS|EXT)_(U\d+_M\d+_L\d+)\.md/i);
|
|
9188
9494
|
if (match) {
|
|
9189
9495
|
const lessonId = match[2].toUpperCase();
|
|
9190
|
-
|
|
9191
|
-
if (!fs2.existsSync(lessonsDir)) {
|
|
9192
|
-
fs2.mkdirSync(lessonsDir, { recursive: true });
|
|
9193
|
-
}
|
|
9194
|
-
fs2.writeFileSync(path3.join(lessonsDir, filename), content, "utf-8");
|
|
9496
|
+
atomicWriteFileSync(path3.join(projectDir, "lessons", lessonId, filename), content);
|
|
9195
9497
|
const legacyContentDir = path3.join(projectDir, "_content", lessonId);
|
|
9196
9498
|
if (fs2.existsSync(legacyContentDir)) {
|
|
9197
|
-
|
|
9499
|
+
atomicWriteFileSync(path3.join(legacyContentDir, filename), content);
|
|
9198
9500
|
}
|
|
9199
9501
|
}
|
|
9200
9502
|
}
|
|
@@ -9285,7 +9587,7 @@ ${lessonTable}
|
|
|
9285
9587
|
}
|
|
9286
9588
|
const stateFile = path3.join(pipelineDir, "state.json");
|
|
9287
9589
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9288
|
-
|
|
9590
|
+
atomicWriteFileSync(stateFile, JSON.stringify(state, null, 2));
|
|
9289
9591
|
}
|
|
9290
9592
|
async updateArtifactState(projectId, taskId, artifactType, update) {
|
|
9291
9593
|
const current = await this.getPipelineState(projectId);
|
|
@@ -10676,6 +10978,306 @@ ${lines.join("\n")}
|
|
|
10676
10978
|
- For example: if canonical section is "Computational Thinking Focus", your heading must be "## [REQUIRED] ${headings["Computational Thinking Focus"] || "Computational Thinking Focus"}".`;
|
|
10677
10979
|
}
|
|
10678
10980
|
|
|
10981
|
+
// src/services/curriculumHorizon.ts
|
|
10982
|
+
init_errors();
|
|
10983
|
+
var DETAILED_BRIDGE_WINDOW = 2;
|
|
10984
|
+
var BOUNDARY_PEEK_WINDOW = 2;
|
|
10985
|
+
function parseAllSessions(plan, frameworkMarkdown) {
|
|
10986
|
+
if (plan) {
|
|
10987
|
+
const rawSessions = Array.isArray(plan.sessions) ? plan.sessions : Array.isArray(plan) ? plan : [];
|
|
10988
|
+
if (rawSessions.length > 0) {
|
|
10989
|
+
return rawSessions.map((s, idx) => ({
|
|
10990
|
+
id: s.id || `L${String(idx + 1).padStart(2, "0")}`,
|
|
10991
|
+
order: typeof s.order === "number" ? s.order : idx + 1,
|
|
10992
|
+
title: s.title || "",
|
|
10993
|
+
prose_objective: s.prose_objective || s.objective || "",
|
|
10994
|
+
new_keywords: Array.isArray(s.new_keywords) ? s.new_keywords : Array.isArray(s.keywords) ? s.keywords : [],
|
|
10995
|
+
prerequisite_keywords: Array.isArray(s.prerequisite_keywords) ? s.prerequisite_keywords : [],
|
|
10996
|
+
depth_assignments: Array.isArray(s.depth_assignments) ? s.depth_assignments : []
|
|
10997
|
+
}));
|
|
10998
|
+
}
|
|
10999
|
+
}
|
|
11000
|
+
if (frameworkMarkdown && typeof frameworkMarkdown === "string") {
|
|
11001
|
+
const lines = frameworkMarkdown.split("\n");
|
|
11002
|
+
let headerCols = [];
|
|
11003
|
+
const sessions = [];
|
|
11004
|
+
for (const line of lines) {
|
|
11005
|
+
const trimmed = line.trim();
|
|
11006
|
+
if (!trimmed.startsWith("|")) continue;
|
|
11007
|
+
const cols = trimmed.split("|").slice(1, -1).map((c) => c.trim());
|
|
11008
|
+
const lower = cols.map((c) => c.toLowerCase());
|
|
11009
|
+
if (lower.some((c) => c.includes("lesson code") || c === "m\xE3 b\xE0i" || c.includes("m\xE3 b\xE0i h\u1ECDc"))) {
|
|
11010
|
+
headerCols = cols;
|
|
11011
|
+
continue;
|
|
11012
|
+
}
|
|
11013
|
+
if (/^[-: |]+$/.test(trimmed.slice(1, -1))) continue;
|
|
11014
|
+
if (cols.length < 3) continue;
|
|
11015
|
+
let lessonCode = "";
|
|
11016
|
+
let title = "";
|
|
11017
|
+
let objective = "";
|
|
11018
|
+
let concept = "";
|
|
11019
|
+
let keywordsStr = "";
|
|
11020
|
+
if (headerCols.length > 0) {
|
|
11021
|
+
const col = (name) => {
|
|
11022
|
+
const idx = headerCols.findIndex((h) => h.toLowerCase().includes(name));
|
|
11023
|
+
return idx >= 0 ? cols[idx] || "" : "";
|
|
11024
|
+
};
|
|
11025
|
+
lessonCode = (col("lesson code") || col("m\xE3 b\xE0i") || cols[1] || "").replace(/\*\*/g, "").trim();
|
|
11026
|
+
title = (col("title") || col("t\xEAn") || cols[2] || "").replace(/\*\*/g, "").trim();
|
|
11027
|
+
objective = col("learning objective") || col("objective") || col("m\u1EE5c ti\xEAu") || "";
|
|
11028
|
+
concept = col("key concept") || col("concept") || col("kh\xE1i ni\u1EC7m") || "";
|
|
11029
|
+
keywordsStr = col("keywords") || col("t\u1EEB kh\xF3a") || "";
|
|
11030
|
+
} else {
|
|
11031
|
+
lessonCode = (cols[1] || "").replace(/\*\*/g, "").trim();
|
|
11032
|
+
title = (cols[2] || "").replace(/\*\*/g, "").trim();
|
|
11033
|
+
objective = cols[5] || "";
|
|
11034
|
+
concept = cols[4] || "";
|
|
11035
|
+
}
|
|
11036
|
+
if (lessonCode && /^[A-Za-z0-9_\-]+$/.test(lessonCode)) {
|
|
11037
|
+
const keywords = keywordsStr ? keywordsStr.split(/[,;\n]/).map((k) => k.trim().replace(/^`|`$/g, "")).filter(Boolean) : concept ? concept.split(/[,;\n]/).map((k) => k.trim().replace(/^`|`$/g, "")).filter(Boolean) : [];
|
|
11038
|
+
sessions.push({
|
|
11039
|
+
id: lessonCode,
|
|
11040
|
+
order: sessions.length + 1,
|
|
11041
|
+
title: title || lessonCode,
|
|
11042
|
+
prose_objective: objective,
|
|
11043
|
+
new_keywords: keywords
|
|
11044
|
+
});
|
|
11045
|
+
}
|
|
11046
|
+
}
|
|
11047
|
+
if (sessions.length > 0) {
|
|
11048
|
+
return sessions;
|
|
11049
|
+
}
|
|
11050
|
+
}
|
|
11051
|
+
return [];
|
|
11052
|
+
}
|
|
11053
|
+
async function extractCurriculumHorizon(opts) {
|
|
11054
|
+
const { plan, frameworkMarkdown, targetLessonId, storage, projectId } = opts;
|
|
11055
|
+
const sessions = parseAllSessions(plan, frameworkMarkdown);
|
|
11056
|
+
if (sessions.length === 0) {
|
|
11057
|
+
throw new CurriculumError({
|
|
11058
|
+
errorCode: "ERR_LESSON_NOT_IN_SOT",
|
|
11059
|
+
lessonId: targetLessonId,
|
|
11060
|
+
message: `[CurriculumHorizon] No sessions could be parsed from CURRICULUM_PLAN.json or CURRICULUM_FRAMEWORK.md. Fail fast \u2014 cannot construct curriculum horizon without SOT.`,
|
|
11061
|
+
suggestedAction: "Ensure CURRICULUM_PLAN.json or CURRICULUM_FRAMEWORK.md is generated and contains valid sessions.",
|
|
11062
|
+
retryable: false
|
|
11063
|
+
});
|
|
11064
|
+
}
|
|
11065
|
+
const targetCodePattern = new RegExp("^" + targetLessonId.replace(/_/g, "[_-]") + "$", "i");
|
|
11066
|
+
const targetIndex = sessions.findIndex(
|
|
11067
|
+
(s) => s.id === targetLessonId || targetCodePattern.test(s.id)
|
|
11068
|
+
);
|
|
11069
|
+
if (targetIndex < 0) {
|
|
11070
|
+
throw new CurriculumError({
|
|
11071
|
+
errorCode: "ERR_LESSON_NOT_IN_SOT",
|
|
11072
|
+
lessonId: targetLessonId,
|
|
11073
|
+
message: `[CurriculumHorizon] Lesson "${targetLessonId}" was not found among the ${sessions.length} planned sessions. Fail fast \u2014 refusing to generate unanchored lesson.`,
|
|
11074
|
+
suggestedAction: `Check lesson id against planned sessions: [${sessions.map((s) => s.id).join(", ")}]`,
|
|
11075
|
+
retryable: false
|
|
11076
|
+
});
|
|
11077
|
+
}
|
|
11078
|
+
const currentSession = sessions[targetIndex];
|
|
11079
|
+
const compactEnd = Math.max(0, targetIndex - DETAILED_BRIDGE_WINDOW);
|
|
11080
|
+
const compactSessions = sessions.slice(0, compactEnd);
|
|
11081
|
+
const masteredKeywords = Array.from(
|
|
11082
|
+
new Set(
|
|
11083
|
+
compactSessions.flatMap((s) => s.new_keywords || []).map((k) => k.trim()).filter(Boolean)
|
|
11084
|
+
)
|
|
11085
|
+
);
|
|
11086
|
+
const masteredConcepts = Array.from(
|
|
11087
|
+
new Set(
|
|
11088
|
+
compactSessions.map((s) => s.title || s.prose_objective || "").map((t) => t.trim()).filter(Boolean)
|
|
11089
|
+
)
|
|
11090
|
+
);
|
|
11091
|
+
const bridgeStart = Math.max(0, targetIndex - DETAILED_BRIDGE_WINDOW);
|
|
11092
|
+
const bridgeSessions = sessions.slice(bridgeStart, targetIndex);
|
|
11093
|
+
const detailedBridge = [];
|
|
11094
|
+
for (const session of bridgeSessions) {
|
|
11095
|
+
const bridgeIndex = sessions.indexOf(session) + 1;
|
|
11096
|
+
const bridge = {
|
|
11097
|
+
lessonId: session.id,
|
|
11098
|
+
lessonIndex: bridgeIndex,
|
|
11099
|
+
title: session.title,
|
|
11100
|
+
proseObjective: session.prose_objective,
|
|
11101
|
+
keywords: session.new_keywords || []
|
|
11102
|
+
};
|
|
11103
|
+
if (storage && projectId) {
|
|
11104
|
+
try {
|
|
11105
|
+
const candidates = [
|
|
11106
|
+
`_content/${session.id.replace(/_L\d+$/, "")}/LESSON_${session.id}.md`,
|
|
11107
|
+
`_content/LESSON_${session.id}.md`,
|
|
11108
|
+
`LESSON_${session.id}.md`
|
|
11109
|
+
];
|
|
11110
|
+
let lessonMd = "";
|
|
11111
|
+
for (const c of candidates) {
|
|
11112
|
+
try {
|
|
11113
|
+
const raw = await storage.readArtifact(projectId, c);
|
|
11114
|
+
if (raw) {
|
|
11115
|
+
lessonMd = raw;
|
|
11116
|
+
break;
|
|
11117
|
+
}
|
|
11118
|
+
} catch {
|
|
11119
|
+
}
|
|
11120
|
+
}
|
|
11121
|
+
if (lessonMd) {
|
|
11122
|
+
const ledger = extractSymbolLedger(lessonMd);
|
|
11123
|
+
if (ledger.primarySymbol || ledger.entryFileName || ledger.keySymbols.length > 0) {
|
|
11124
|
+
bridge.symbolLedger = {
|
|
11125
|
+
primaryStructOrClass: ledger.primarySymbol,
|
|
11126
|
+
mainEntryFile: ledger.entryFileName,
|
|
11127
|
+
keyVariables: ledger.keySymbols
|
|
11128
|
+
};
|
|
11129
|
+
}
|
|
11130
|
+
}
|
|
11131
|
+
} catch {
|
|
11132
|
+
}
|
|
11133
|
+
}
|
|
11134
|
+
detailedBridge.push(bridge);
|
|
11135
|
+
}
|
|
11136
|
+
const peekStart = targetIndex + 1;
|
|
11137
|
+
const peekEnd = Math.min(sessions.length, peekStart + BOUNDARY_PEEK_WINDOW);
|
|
11138
|
+
const boundaryPeek = sessions.slice(peekStart, peekEnd).map((s, idx) => ({
|
|
11139
|
+
lessonId: s.id,
|
|
11140
|
+
lessonIndex: peekStart + idx + 1,
|
|
11141
|
+
title: s.title,
|
|
11142
|
+
keywords: s.new_keywords || []
|
|
11143
|
+
}));
|
|
11144
|
+
return {
|
|
11145
|
+
targetLessonId,
|
|
11146
|
+
targetLessonIndex: targetIndex + 1,
|
|
11147
|
+
totalLessons: sessions.length,
|
|
11148
|
+
targetTitle: currentSession.title,
|
|
11149
|
+
targetKeywords: currentSession.new_keywords || [],
|
|
11150
|
+
compactMasterySet: {
|
|
11151
|
+
masteredKeywords,
|
|
11152
|
+
masteredConcepts
|
|
11153
|
+
},
|
|
11154
|
+
detailedBridge,
|
|
11155
|
+
boundaryPeek
|
|
11156
|
+
};
|
|
11157
|
+
}
|
|
11158
|
+
function renderHorizonPromptBlock(horizon) {
|
|
11159
|
+
const {
|
|
11160
|
+
targetLessonId,
|
|
11161
|
+
targetLessonIndex,
|
|
11162
|
+
totalLessons,
|
|
11163
|
+
targetTitle,
|
|
11164
|
+
targetKeywords,
|
|
11165
|
+
compactMasterySet,
|
|
11166
|
+
detailedBridge,
|
|
11167
|
+
boundaryPeek
|
|
11168
|
+
} = horizon;
|
|
11169
|
+
const lines = [
|
|
11170
|
+
`# \u{1F9ED} CURRICULUM HORIZON & SCAFFOLDING MATRIX (Lesson ${targetLessonIndex}/${totalLessons}: "${targetTitle}" [${targetLessonId}])`
|
|
11171
|
+
];
|
|
11172
|
+
if (compactMasterySet.masteredKeywords.length > 0 || compactMasterySet.masteredConcepts.length > 0) {
|
|
11173
|
+
const rawKeywords = compactMasterySet.masteredKeywords;
|
|
11174
|
+
const displayedKeywords = rawKeywords.length > 20 ? rawKeywords.slice(-20) : rawKeywords;
|
|
11175
|
+
const vocab = displayedKeywords.map((k) => `\`${k}\``).join(", ");
|
|
11176
|
+
const moreSuffix = rawKeywords.length > 20 ? ` *(+${rawKeywords.length - 20} earlier terms)*` : "";
|
|
11177
|
+
const concepts = compactMasterySet.masteredConcepts.length > 0 ? `
|
|
11178
|
+
- **Prior Concept Foundations:** ${compactMasterySet.masteredConcepts.slice(-3).join("; ")}` : "";
|
|
11179
|
+
lines.push(
|
|
11180
|
+
`
|
|
11181
|
+
## 1. \u{1F393} MASTERED VOCABULARY (Prior Lessons 1..${Math.max(1, targetLessonIndex - 3)} \u2014 Compact Set):`,
|
|
11182
|
+
`- **Mastered Terms & Syntax:** ${vocab || "(Core fundamentals)"}${moreSuffix}${concepts}`
|
|
11183
|
+
);
|
|
11184
|
+
} else if (targetLessonIndex === 1) {
|
|
11185
|
+
lines.push(
|
|
11186
|
+
`
|
|
11187
|
+
## 1. \u{1F393} PRIOR KNOWLEDGE FRONTIER:`,
|
|
11188
|
+
`- **Entry Point:** Inaugural lesson (Lesson 1/${totalLessons}). Students have no prior course vocabulary. All concepts must be introduced from baseline.`
|
|
11189
|
+
);
|
|
11190
|
+
}
|
|
11191
|
+
if (detailedBridge.length > 0) {
|
|
11192
|
+
lines.push(`
|
|
11193
|
+
## 2. \u{1F309} IMMEDIATE PREDECESSOR CONTEXT (Bridge Lessons):`);
|
|
11194
|
+
for (const bridge of detailedBridge) {
|
|
11195
|
+
lines.push(`### Lesson ${bridge.lessonIndex} (${bridge.lessonId}): ${bridge.title}`);
|
|
11196
|
+
if (bridge.proseObjective) {
|
|
11197
|
+
const obj = bridge.proseObjective.length > 120 ? bridge.proseObjective.slice(0, 117) + "..." : bridge.proseObjective;
|
|
11198
|
+
lines.push(`- **Objective:** ${obj}`);
|
|
11199
|
+
}
|
|
11200
|
+
if (bridge.keywords.length > 0) {
|
|
11201
|
+
lines.push(`- **Keywords:** ${bridge.keywords.map((k) => `\`${k}\``).join(", ")}`);
|
|
11202
|
+
}
|
|
11203
|
+
if (bridge.symbolLedger) {
|
|
11204
|
+
const parts = [];
|
|
11205
|
+
if (bridge.symbolLedger.primaryStructOrClass) {
|
|
11206
|
+
parts.push(`Primary Struct: \`${bridge.symbolLedger.primaryStructOrClass}\``);
|
|
11207
|
+
}
|
|
11208
|
+
if (bridge.symbolLedger.mainEntryFile) {
|
|
11209
|
+
parts.push(`Entry File: \`${bridge.symbolLedger.mainEntryFile}\``);
|
|
11210
|
+
}
|
|
11211
|
+
if (bridge.symbolLedger.keyVariables?.length) {
|
|
11212
|
+
parts.push(`Symbols: ${bridge.symbolLedger.keyVariables.map((v) => `\`${v}\``).join(", ")}`);
|
|
11213
|
+
}
|
|
11214
|
+
if (parts.length > 0) {
|
|
11215
|
+
lines.push(`- **Code Symbol Ledger:** ${parts.join(" | ")}`);
|
|
11216
|
+
}
|
|
11217
|
+
}
|
|
11218
|
+
}
|
|
11219
|
+
lines.push(
|
|
11220
|
+
`\u{1F449} INSTRUCTION: Seamlessly connect the opening Hook and Guided Practice by referencing the student's recent work from Lesson ${detailedBridge[detailedBridge.length - 1]?.lessonIndex}.`
|
|
11221
|
+
);
|
|
11222
|
+
}
|
|
11223
|
+
const currentKeywordsStr = targetKeywords.length > 0 ? targetKeywords.map((k) => `\`${k}\``).join(", ") : "`Current Lesson Concepts`";
|
|
11224
|
+
lines.push(
|
|
11225
|
+
`
|
|
11226
|
+
## 3. \u{1F3AF} ALLOWED DESIGN SPACE (Positive-Only Allow List):`,
|
|
11227
|
+
`- **Student Toolkit:** Mastered Vocabulary + Immediate Bridge Keywords + Current Lesson Scope (${currentKeywordsStr}).`,
|
|
11228
|
+
`- **MANDATE:** ALL extension challenges (EXT), hands-on activities (ACT), and assessment questions (QUIZ) MUST be 100% solvable using ONLY items within this toolkit. Do NOT require unintroduced APIs!`
|
|
11229
|
+
);
|
|
11230
|
+
if (boundaryPeek.length > 0) {
|
|
11231
|
+
const nextLesson = boundaryPeek[0];
|
|
11232
|
+
const nextKeywords = nextLesson.keywords.length > 0 ? nextLesson.keywords.map((k) => `\`${k}\``).join(", ") : "upcoming features";
|
|
11233
|
+
lines.push(
|
|
11234
|
+
`
|
|
11235
|
+
## 4. \u{1F6A7} BOUNDARY (Next Lesson Peek):`,
|
|
11236
|
+
`- **Upcoming Lesson ${nextLesson.lessonIndex} ("${nextLesson.title}"):** Introduces ${nextKeywords}.`,
|
|
11237
|
+
`- **BOUNDARY MANDATE:** These concepts are NOT yet available to the student. Do not introduce or require these future concepts.`
|
|
11238
|
+
);
|
|
11239
|
+
}
|
|
11240
|
+
return lines.join("\n");
|
|
11241
|
+
}
|
|
11242
|
+
function validateHorizonCompliance(artifactContent, horizon) {
|
|
11243
|
+
const issues = [];
|
|
11244
|
+
const forbiddenMatches = [];
|
|
11245
|
+
if (!artifactContent || horizon.boundaryPeek.length === 0) {
|
|
11246
|
+
return { compliant: true, issues: [], forbiddenMatches: [] };
|
|
11247
|
+
}
|
|
11248
|
+
const contentLower = artifactContent.toLowerCase();
|
|
11249
|
+
const immediateNext = horizon.boundaryPeek[0];
|
|
11250
|
+
if (immediateNext && immediateNext.keywords.length > 0) {
|
|
11251
|
+
for (const kw of immediateNext.keywords) {
|
|
11252
|
+
const trimmed = kw.trim().toLowerCase();
|
|
11253
|
+
if (trimmed.length <= 2) continue;
|
|
11254
|
+
const pattern = new RegExp(`\\b${trimmed.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "i");
|
|
11255
|
+
if (pattern.test(contentLower)) {
|
|
11256
|
+
const inMastered = horizon.compactMasterySet.masteredKeywords.some(
|
|
11257
|
+
(m) => m.toLowerCase() === trimmed
|
|
11258
|
+
);
|
|
11259
|
+
const inBridge = horizon.detailedBridge.some(
|
|
11260
|
+
(b) => b.keywords.some((bk) => bk.toLowerCase() === trimmed)
|
|
11261
|
+
);
|
|
11262
|
+
const inCurrent = horizon.targetKeywords.some(
|
|
11263
|
+
(ck) => ck.toLowerCase() === trimmed
|
|
11264
|
+
);
|
|
11265
|
+
if (!inMastered && !inBridge && !inCurrent) {
|
|
11266
|
+
forbiddenMatches.push(kw);
|
|
11267
|
+
issues.push(
|
|
11268
|
+
`Artifact contains boundary concept "${kw}" scheduled for future Lesson ${immediateNext.lessonIndex} ("${immediateNext.title}").`
|
|
11269
|
+
);
|
|
11270
|
+
}
|
|
11271
|
+
}
|
|
11272
|
+
}
|
|
11273
|
+
}
|
|
11274
|
+
return {
|
|
11275
|
+
compliant: issues.length === 0,
|
|
11276
|
+
issues,
|
|
11277
|
+
forbiddenMatches
|
|
11278
|
+
};
|
|
11279
|
+
}
|
|
11280
|
+
|
|
10679
11281
|
// src/services/contextBuilder.ts
|
|
10680
11282
|
var DEFAULT_LESSON_PRIORITIES = [
|
|
10681
11283
|
"Symbol & Identifier Ledger",
|
|
@@ -10685,6 +11287,13 @@ var DEFAULT_LESSON_PRIORITIES = [
|
|
|
10685
11287
|
"Learning Objectives & Evidence",
|
|
10686
11288
|
"Activity Sequence"
|
|
10687
11289
|
];
|
|
11290
|
+
var SATELLITE_LESSON_PRIORITIES = [
|
|
11291
|
+
"Artifact Contract",
|
|
11292
|
+
"A. Lesson Design Plan",
|
|
11293
|
+
"B. Lesson Flow",
|
|
11294
|
+
"Learning Objectives & Evidence",
|
|
11295
|
+
"Activity Sequence"
|
|
11296
|
+
];
|
|
10688
11297
|
var DEFAULT_KX_PRIORITIES = [
|
|
10689
11298
|
"Key Terms",
|
|
10690
11299
|
"Concept Narratives",
|
|
@@ -25490,6 +26099,47 @@ async function produceSingleLesson(storage, projectId, lessonId, options = {}) {
|
|
|
25490
26099
|
|
|
25491
26100
|
[CURRICULUM FRAMEWORK EXCERPT]:
|
|
25492
26101
|
${buildFrameworkExcerptForLesson(framework, lessonId)}`;
|
|
26102
|
+
let horizon = null;
|
|
26103
|
+
let horizonBlock = "";
|
|
26104
|
+
try {
|
|
26105
|
+
let planObj = null;
|
|
26106
|
+
const planRaw = await storage.readArtifact(projectId, "_sot/CURRICULUM_PLAN.json");
|
|
26107
|
+
if (planRaw) {
|
|
26108
|
+
try {
|
|
26109
|
+
planObj = JSON.parse(planRaw);
|
|
26110
|
+
} catch {
|
|
26111
|
+
}
|
|
26112
|
+
}
|
|
26113
|
+
horizon = await extractCurriculumHorizon({
|
|
26114
|
+
plan: planObj,
|
|
26115
|
+
frameworkMarkdown: framework,
|
|
26116
|
+
targetLessonId: lessonCode,
|
|
26117
|
+
storage,
|
|
26118
|
+
projectId
|
|
26119
|
+
});
|
|
26120
|
+
if (horizon) {
|
|
26121
|
+
horizonBlock = `
|
|
26122
|
+
|
|
26123
|
+
${renderHorizonPromptBlock(horizon)}`;
|
|
26124
|
+
}
|
|
26125
|
+
} catch (hErr) {
|
|
26126
|
+
console.warn(`[produceSingleLesson] Notice: Curriculum Horizon extraction:`, hErr?.message || hErr);
|
|
26127
|
+
}
|
|
26128
|
+
const buildGroundTruthBlock = () => {
|
|
26129
|
+
const parts = [];
|
|
26130
|
+
if (expositionContext) {
|
|
26131
|
+
parts.push(`### KNOWLEDGE_EXPOSITION (CANONICAL KNOWLEDGE \u2014 teach from this, do not contradict)
|
|
26132
|
+
${expositionContext}`);
|
|
26133
|
+
}
|
|
26134
|
+
if (effectiveRefPack) {
|
|
26135
|
+
parts.push(`### REFERENCE PACK GROUND TRUTH
|
|
26136
|
+
${effectiveRefPack}`);
|
|
26137
|
+
}
|
|
26138
|
+
return parts.length > 0 ? `
|
|
26139
|
+
|
|
26140
|
+
[GROUND TRUTH]:
|
|
26141
|
+
${parts.join("\n\n")}` : "";
|
|
26142
|
+
};
|
|
25493
26143
|
const glossaryBlock = glossaryContext ? `
|
|
25494
26144
|
|
|
25495
26145
|
[GLOSSARY TERMS (use these exact definitions)]:
|
|
@@ -25497,21 +26147,14 @@ ${glossaryContext}` : "";
|
|
|
25497
26147
|
const standardsBlock = standardsContext ? `
|
|
25498
26148
|
|
|
25499
26149
|
${standardsContext}` : "";
|
|
25500
|
-
const expositionBlock = expositionContext ? `
|
|
25501
|
-
|
|
25502
|
-
[KNOWLEDGE_EXPOSITION (CANONICAL KNOWLEDGE \u2014 teach from this, do not contradict)]:
|
|
25503
|
-
${expositionContext}` : "";
|
|
25504
26150
|
const sessionSliceBlock = sessionSliceContext ? `
|
|
25505
26151
|
|
|
25506
26152
|
${sessionSliceContext}` : "";
|
|
25507
|
-
const assembleCommonContext = (
|
|
26153
|
+
const assembleCommonContext = (sg) => `${baseContextPrefix}
|
|
25508
26154
|
|
|
25509
26155
|
[CONTENT STYLE GUIDE EXCERPT]:
|
|
25510
|
-
${sg}
|
|
25511
|
-
|
|
25512
|
-
[REFERENCE PACK GROUND TRUTH]:
|
|
25513
|
-
${ref}${standardsBlock}${glossaryBlock}${expositionBlock}${sessionSliceBlock}`;
|
|
25514
|
-
let commonContext = assembleCommonContext(effectiveRefPack, effectiveStyleGuide);
|
|
26156
|
+
${sg}${standardsBlock}${glossaryBlock}${buildGroundTruthBlock()}${sessionSliceBlock}${horizonBlock}`;
|
|
26157
|
+
let commonContext = assembleCommonContext(effectiveStyleGuide);
|
|
25515
26158
|
const MAX_COMPOSITE_PROMPT_CHARS = 3e4;
|
|
25516
26159
|
const runnerOptions = options.customInference ? { customInference: options.customInference } : {};
|
|
25517
26160
|
if (commonContext.length > MAX_COMPOSITE_PROMPT_CHARS && effectiveRefPack.length > 1e3) {
|
|
@@ -25522,14 +26165,14 @@ ${ref}${standardsBlock}${glossaryBlock}${expositionBlock}${sessionSliceBlock}`;
|
|
|
25522
26165
|
],
|
|
25523
26166
|
budget: 1e3
|
|
25524
26167
|
}).excerpt;
|
|
25525
|
-
commonContext = assembleCommonContext(
|
|
26168
|
+
commonContext = assembleCommonContext(effectiveStyleGuide);
|
|
25526
26169
|
}
|
|
25527
26170
|
if (commonContext.length > MAX_COMPOSITE_PROMPT_CHARS && effectiveStyleGuide.length > 1e3) {
|
|
25528
26171
|
effectiveStyleGuide = buildSectionAwareExcerpt(styleGuide, {
|
|
25529
26172
|
priorities: ["Voice & Tone", "Standard Terminology (Glossary)"],
|
|
25530
26173
|
budget: 1e3
|
|
25531
26174
|
}).excerpt;
|
|
25532
|
-
commonContext = assembleCommonContext(
|
|
26175
|
+
commonContext = assembleCommonContext(effectiveStyleGuide);
|
|
25533
26176
|
}
|
|
25534
26177
|
onProgress?.("@content", `[CONTEXT] Composite prompt ready (${commonContext.length} chars, adaptive budget <= ${MAX_COMPOSITE_PROMPT_CHARS})`, {
|
|
25535
26178
|
type: "progress",
|
|
@@ -25880,7 +26523,7 @@ ${currentContent}` }],
|
|
|
25880
26523
|
});
|
|
25881
26524
|
}
|
|
25882
26525
|
const lessonExcerptResult = buildSectionAwareExcerpt(lessonContent, {
|
|
25883
|
-
priorities:
|
|
26526
|
+
priorities: SATELLITE_LESSON_PRIORITIES,
|
|
25884
26527
|
budget: 12e3,
|
|
25885
26528
|
sectionLanguageContract: slcMarkdown,
|
|
25886
26529
|
artifactType: "LESSON"
|
|
@@ -26070,6 +26713,7 @@ ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
|
|
|
26070
26713
|
} catch {
|
|
26071
26714
|
}
|
|
26072
26715
|
const { executeSlideProductionWorkflow: executeSlideProductionWorkflow2 } = await Promise.resolve().then(() => (init_slideProductionWorkflow(), slideProductionWorkflow_exports));
|
|
26716
|
+
const slideGroundContext = `${commonContext}${symbolLedgerBlock}`;
|
|
26073
26717
|
const workflowResult = await executeSlideProductionWorkflow2({
|
|
26074
26718
|
lessonMarkdown: lessonContent || "",
|
|
26075
26719
|
lessonCode,
|
|
@@ -26078,6 +26722,7 @@ ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
|
|
|
26078
26722
|
language: targetLang || "Vietnamese",
|
|
26079
26723
|
languageDirective,
|
|
26080
26724
|
headingDirective: buildHeadingDirective("SLIDE", slcMarkdown, targetLang),
|
|
26725
|
+
groundContext: slideGroundContext,
|
|
26081
26726
|
satelliteContext,
|
|
26082
26727
|
runnerOptions,
|
|
26083
26728
|
onProgress: (agent, msg, meta) => {
|
|
@@ -26086,7 +26731,7 @@ ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
|
|
|
26086
26731
|
});
|
|
26087
26732
|
let deckJson = workflowResult.deckJson;
|
|
26088
26733
|
const markdownWrapper = workflowResult.markdownWrapper;
|
|
26089
|
-
let validation = presentationKitAi?.validateHtmlSlideDeck ? presentationKitAi.validateHtmlSlideDeck(deckJson, true) : deckJson && Array.isArray(deckJson.slides) ? { valid: true, score: 95, issues: [], slideCount: deckJson.slides.length} : { valid: false, score: 0, issues: [{ message: "Malformed JSON slide deck" }]
|
|
26734
|
+
let validation = presentationKitAi?.validateHtmlSlideDeck ? presentationKitAi.validateHtmlSlideDeck(deckJson, true) : deckJson && Array.isArray(deckJson.slides) ? { valid: true, score: 95, issues: [], slideCount: deckJson.slides.length} : { valid: false, score: 0, issues: [{ message: "Malformed JSON slide deck" }]};
|
|
26090
26735
|
await storage.saveArtifact(projectId, slideRelPath, markdownWrapper);
|
|
26091
26736
|
producedArtifacts.push(`SLIDE_${lessonCode}.md`);
|
|
26092
26737
|
if (deckJson) {
|
|
@@ -26106,21 +26751,45 @@ ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
|
|
|
26106
26751
|
}
|
|
26107
26752
|
}
|
|
26108
26753
|
}
|
|
26109
|
-
const
|
|
26110
|
-
const
|
|
26111
|
-
|
|
26112
|
-
|
|
26113
|
-
|
|
26114
|
-
|
|
26115
|
-
|
|
26116
|
-
|
|
26117
|
-
|
|
26118
|
-
|
|
26119
|
-
|
|
26120
|
-
|
|
26121
|
-
|
|
26122
|
-
|
|
26123
|
-
|
|
26754
|
+
const structuralOk = Boolean(validation.valid && (validation.score ?? 100) >= 80);
|
|
26755
|
+
const structuralScore = validation.score ?? (structuralOk ? 95 : 50);
|
|
26756
|
+
const gateMode = gateModeFor(gates, "SLIDE");
|
|
26757
|
+
if (!structuralOk) {
|
|
26758
|
+
await storage.updateArtifactState(projectId, lessonCode, "SLIDE", {
|
|
26759
|
+
state: "rejected",
|
|
26760
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26761
|
+
contentHash: computeContentHash(markdownWrapper),
|
|
26762
|
+
review: {
|
|
26763
|
+
decision: "NEEDS_REVISION",
|
|
26764
|
+
reviewedBy: "@heuristic-linter",
|
|
26765
|
+
reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26766
|
+
score: structuralScore,
|
|
26767
|
+
critique: `HTML Slide Deck failed schema validation: ${(validation.issues || []).map((i) => i.message).join("; ")}`
|
|
26768
|
+
}
|
|
26769
|
+
});
|
|
26770
|
+
onProgress?.("@reviewer", `\u26A0\uFE0F SLIDE structural pre-check FAILED (${structuralScore}/100) [html-deck schema issues]`);
|
|
26771
|
+
} else {
|
|
26772
|
+
await storage.updateArtifactState(projectId, lessonCode, "SLIDE", {
|
|
26773
|
+
state: gateMode === "LLM_JUDGE" ? "pending" : "completed",
|
|
26774
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26775
|
+
contentHash: computeContentHash(markdownWrapper)
|
|
26776
|
+
});
|
|
26777
|
+
onProgress?.("@reviewer", gateMode === "LLM_JUDGE" ? `\u2705 SLIDE structural pre-check PASS (${structuralScore}/100) \u2014 handing content review to LLM-as-Judge gate` : `\u2705 SLIDE structural pre-check PASS (${structuralScore}/100) [gate=${gateMode}, no LLM judge]`);
|
|
26778
|
+
const deckTextForJudge = Array.isArray(deckJson?.slides) ? deckJson.slides.map((s, i) => {
|
|
26779
|
+
const slotLines = Object.entries(s.slots || {}).map(([k, v]) => {
|
|
26780
|
+
if (Array.isArray(v)) return `- ${k}:
|
|
26781
|
+
${v.map((item) => typeof item === "object" ? ` - ${JSON.stringify(item)}` : ` - ${item}`).join("\n")}`;
|
|
26782
|
+
if (v && typeof v === "object") return `- ${k}: ${JSON.stringify(v, null, 1)}`;
|
|
26783
|
+
return `- ${k}: ${v}`;
|
|
26784
|
+
}).join("\n");
|
|
26785
|
+
return `## Slide ${i + 1} [${s.layoutId}]
|
|
26786
|
+
${slotLines}
|
|
26787
|
+
|
|
26788
|
+
Presenter Notes:
|
|
26789
|
+
${s.notes || "(none)"}`;
|
|
26790
|
+
}).join("\n\n") : String(markdownWrapper);
|
|
26791
|
+
await judgeSat("SLIDE", deckTextForJudge);
|
|
26792
|
+
}
|
|
26124
26793
|
} else {
|
|
26125
26794
|
const canonicalSlideTemplate = loadCurriculumTemplate("SLIDE_template.md");
|
|
26126
26795
|
const templateScaffold = canonicalSlideTemplate || `---
|
|
@@ -26405,14 +27074,12 @@ ${buildHeadingDirective("CODE", slcMarkdown, targetLang)}`;
|
|
|
26405
27074
|
c3: "### Challenge 3: [Name] (Difficulty: \u2B50\u2B50\u2B50\u2B50\u2B50) \u2014 Extension Milestones (Level 1: Ninja \u2192 Level 2: Guru \u2192 Level 3: Master)",
|
|
26406
27075
|
meta: "## [REQUIRED] Metacognitive Deep Dive & Engineering Trade-offs"
|
|
26407
27076
|
};
|
|
26408
|
-
const
|
|
26409
|
-
|
|
26410
|
-
|
|
26411
|
-
|
|
26412
|
-
|
|
26413
|
-
|
|
26414
|
-
- STRICTLY FORBIDDEN: NEVER introduce advanced mechanisms from future lessons (No complex event buses, No remote network/API calls, No persistent databases, No async concurrency, No out-of-scope hardware/sensors).` : `
|
|
26415
|
-
4. ZPD SCOPE: Focus on architectural edge cases, algorithmic optimization, and synthesis of learned concepts up to Lesson #${lessonIdx}.`;
|
|
27077
|
+
const zpdCeilingPrompt = horizon ? `
|
|
27078
|
+
4. \u{1F3AF} CURRICULUM HORIZON ALLOWED SPACE & BOUNDARY MANDATE:
|
|
27079
|
+
- Student's COMPLETE allowed toolkit = Mastered Vocabulary + Immediate Bridge + Current Lesson Scope (${horizon.targetKeywords.join(", ") || "Current Lesson Concepts"}).
|
|
27080
|
+
- All extension challenges MUST be 100% solvable using ONLY items within this toolkit.
|
|
27081
|
+
${horizon.boundaryPeek.length > 0 ? `- STRICT BOUNDARY: Upcoming Lesson ${horizon.boundaryPeek[0].lessonIndex} introduces "${horizon.boundaryPeek[0].title}" (${horizon.boundaryPeek[0].keywords.join(", ")}). These are STRICTLY OUT OF SCOPE. Do NOT introduce or require these future APIs.` : ""}` : `
|
|
27082
|
+
4. ZPD SCOPE: Focus on architectural edge cases, algorithmic optimization, and creative variations within current and past lesson concepts.`;
|
|
26416
27083
|
const extPrompt = `You are @activity (Lead STEM Specialist & Differentiated Extension Designer).
|
|
26417
27084
|
Based on Master Lesson Plan \`LESSON_${lessonCode}.md\`, author the advanced extension challenge: \`EXT_${lessonCode}.md\`.
|
|
26418
27085
|
|
|
@@ -26984,6 +27651,20 @@ async function generateSingleArtifact(req) {
|
|
|
26984
27651
|
- Entry Source File: \`${symbolLedger.entryFileName || symbolLedger.primarySymbol + ".swift"}\`
|
|
26985
27652
|
- Key Identifiers to inherit: ${symbolLedger.keySymbols.map((s) => `\`${s}\``).join(", ")}
|
|
26986
27653
|
- INVARIANT: You MUST use these exact identifier names in all code examples, exercises, and starter templates. Do NOT invent conflicting struct or class names.` : "";
|
|
27654
|
+
let horizon = contextSot.horizon || null;
|
|
27655
|
+
if (!horizon && (contextSot.plan || contextSot.framework) && lessonId) {
|
|
27656
|
+
try {
|
|
27657
|
+
horizon = await extractCurriculumHorizon({
|
|
27658
|
+
plan: contextSot.plan,
|
|
27659
|
+
frameworkMarkdown: contextSot.framework,
|
|
27660
|
+
targetLessonId: lessonId
|
|
27661
|
+
});
|
|
27662
|
+
} catch {
|
|
27663
|
+
}
|
|
27664
|
+
}
|
|
27665
|
+
const horizonPrompt = horizon ? `
|
|
27666
|
+
|
|
27667
|
+
${renderHorizonPromptBlock(horizon)}` : "";
|
|
26987
27668
|
const systemPrompt = `You are ${meta.persona}, an expert Curriculum & Pedagogical Specialist in the Curriculum OS Multi-Agent Team.
|
|
26988
27669
|
Your task is to author a canonical, publication-grade learning artifact of type "${artifactType.toUpperCase()}".
|
|
26989
27670
|
|
|
@@ -26997,7 +27678,7 @@ ${headingDirective}
|
|
|
26997
27678
|
6. DOMAIN & TECH STACK GUARDRAILS:
|
|
26998
27679
|
${domainGuardrail}
|
|
26999
27680
|
${symbolLedgerPrompt}
|
|
27000
|
-
8. OUTPUT INTEGRITY: Output clean Markdown starting directly with YAML frontmatter. Do not wrap entire response in triple backticks.${artifactSpecializedPrompt}${mediaPolicy ? `
|
|
27681
|
+
8. OUTPUT INTEGRITY: Output clean Markdown starting directly with YAML frontmatter. Do not wrap entire response in triple backticks.${artifactSpecializedPrompt}${horizonPrompt}${mediaPolicy ? `
|
|
27001
27682
|
|
|
27002
27683
|
IMAGE PLANNING (media ledger) \u2014 QUOTA GEN: t\u1ED1i \u0111a ${mediaPolicy.maxGenImagesPerArtifact} \u1EA3nh AI cho artifact n\xE0y (\u1EA3nh search kho kh\xF4ng gi\u1EDBi h\u1EA1n).
|
|
27003
27684
|
Khi n\u1ED9i dung c\u1EA7n minh h\u1ECDa (diagram quy tr\xECnh, s\u01A1 \u0111\u1ED3 kh\xE1i ni\u1EC7m, step-by-step visual), ch\xE8n placeholder \u0111\xFAng format [IMAGE: slug] (slug ch\u1EEF th\u01B0\u1EDDng-g\u1EA1ch ngang, unique trong b\xE0i, vd img-for-loop-diagram) T\u1EA0I \u0110\xDANG CH\u1ED6 c\u1EA7n \u1EA3nh, tr\xEAn d\xF2ng ri\xEAng. KH\xD4NG t\u1EF1 sinh \u1EA3nh, KH\xD4NG d\xF9ng markdown image \u2014 placeholder s\u1EBD \u0111\u01B0\u1EE3c thay b\u1EB1ng \u1EA3nh th\u1EADt sau khi Media Curator duy\u1EC7t. Ch\u1EC9 \u0111\u1EB7t cho \u1EA3nh TH\u1EF0C S\u1EF0 c\u1EA7n thi\u1EBFt.` : ""}`;
|
|
@@ -27478,13 +28159,9 @@ ${includeUnitTests ? "- Unit Testing: Provide automated assertions or test runne
|
|
|
27478
28159
|
- Exact quantities calculated for ${studentCount} students.
|
|
27479
28160
|
- Component specifications, estimated unit cost, and affordable alternatives.`;
|
|
27480
28161
|
case "ext": {
|
|
27481
|
-
const
|
|
27482
|
-
|
|
27483
|
-
|
|
27484
|
-
const zpdCeilingRule = isEarlyLesson ? `- \u{1F6D1} ZPD COMPLEXITY CEILING (FOUNDATIONAL LESSON #${lessonIdx}):
|
|
27485
|
-
\u2022 SCOPE LOCK: This is an early foundational lesson. The extension challenge MUST focus on creative design variations, parameterization, or edge cases of the current lesson concepts ONLY.
|
|
27486
|
-
\u2022 STRICTLY FORBIDDEN: NEVER introduce advanced mechanisms from future lessons (No complex event buses, No remote network/API calls, No persistent databases, No async concurrency, No out-of-scope hardware/sensors).` : `- \u{1F680} ZPD ADVANCED CHALLENGE (LESSON #${lessonIdx}):
|
|
27487
|
-
\u2022 Focus on architectural edge cases, algorithmic optimization, and synthesis of learned concepts up to Lesson #${lessonIdx}.`;
|
|
28162
|
+
const zpdCeilingRule = `- \u{1F3AF} CURRICULUM HORIZON ALLOWED SPACE & BOUNDARY MANDATE:
|
|
28163
|
+
\u2022 SCOPE LOCK: All extension challenges MUST be 100% solvable using ONLY items from the student's Mastered Vocabulary and Current Lesson Scope.
|
|
28164
|
+
\u2022 STRICTLY FORBIDDEN: NEVER introduce unintroduced APIs or mechanisms from upcoming lessons (No complex event buses, No remote network/API calls, No persistent databases, No async concurrency, No out-of-scope hardware/sensors unless explicitly part of the allowed toolkit).`;
|
|
27488
28165
|
return `
|
|
27489
28166
|
### \u{1F680} EXTENSION CHALLENGE ARCHITECTURE INVARIANTS:
|
|
27490
28167
|
${zpdCeilingRule}
|
|
@@ -31115,6 +31792,6 @@ function renderMediaPlaceholder(entry) {
|
|
|
31115
31792
|
return `> \u{1F5BC}\uFE0F [\u1EA2nh \u0111ang ch\u1EDD: ${entry.name} \u2014 s\u1EBD \u0111\u01B0\u1EE3c t\u1EA1o sau khi duy\u1EC7t media]`;
|
|
31116
31793
|
}
|
|
31117
31794
|
|
|
31118
|
-
export { ACT_TEMPLATE, ARTIFACT_DEPENDENCY_ROUTING, ARTIFACT_EXECUTION_ORDER, AcademicAuditor, ActiveLearningWorkflowSchema, ActivityLabSchema, ActivitySeqRowSchema, ActivityStepSchema, ArtifactContractRowSchema, AssessmentMapRowSchema, AssessmentObjectiveSchema, BELL_RINGER_TEMPLATE, BLOOM_ACTION_VERBS, BOM_TEMPLATE, BUNDLED_STANDARDS_PACK_IDS, BellRingerDaySchema, BellRingerSchema, BloomHintSchema, BloomLevelSchema, BloomTaxonomyEvaluator, BronzeTierSchema, CERConclusionSchema, CHOICE_BOARD_TEMPLATE, CODE_LAB_TEMPLATE, CURRICULUM_SLASH_COMMANDS, CardTierEnum, ChoiceBoardRubricRowSchema, ChoiceBoardSchema, ChoiceRuleSchema, ChoiceSquareSchema, ClassificationSchema, CodeHardwareFeasibilityEvaluator, CodeLabSchema, CodeSnippetSchema, CompetencyRubricRowSchema, ComputationalThinkingSchema, ConstructiveAlignmentEvaluator, CoreConceptSchema, CourseObjectiveSchema, CoverageReportSchema, CrossArtifactDriftEvaluator, CurriculumArtifactSchema, CurriculumError, CurriculumPlanSchema, CurriculumQualityReportSchema, DEFAULT_ARTIFACT_STREAM_IDLE_MS, DEFAULT_ARTIFACT_STREAM_TOTAL_MS, DEFAULT_ENABLED_PROVIDERS, DEFAULT_GATE_SETTINGS, DEFAULT_KX_PRIORITIES, DEFAULT_LESSON_PRIORITIES, DEFAULT_STREAM_IDLE_MS, DEFAULT_STREAM_TOTAL_MS, DEFAULT_VIETNAMESE_SECTION_HEADINGS, DependencyEdgeSchema, DepthAssignmentSchema, DepthLevelSchema, DeterministicPipelineRunner, DeterministicStructuralLinter, DiagnosticQuestionSchema, DiagnosticQuizSchema, EDPPhaseEnum, EXIT_TICKET_TEMPLATE, EXPOSITION_REL, EXT_TEMPLATE, EntryLevelSchema, ExitTicketBugHuntSchema, ExitTicketMetacognitionSchema, ExitTicketQuickItemSchema, ExitTicketRecallPromptSchema, ExitTicketSchema, ExperimentalDesignSchema, ExpositionApprovalError, ExtensionChallengeSchema, ExtensionSchema, FileSystemCurriculumAdapter, FiveEFlowPhaseSchema, FiveEInstructionalEvaluator, FiveEPhaseEnum, FrameworkMappingSchema, FrameworkPackManifestSchema, FrameworkPackSchema, FrameworkStatementSchema, GLOSSARY_TEMPLATE, GRAPHIC_ORGANIZER_TEMPLATE, GeneratedSlideArraySchema, GeneratedSlideSchema, GlossaryQuickRefRowSchema, GlossarySchema, GlossaryTermSchema, GoldTierSchema, GradeBandSchema, GraphicOrganizerItemSchema, GraphicOrganizerSchema, HANDOUT_TEMPLATE, HandoutSchema, HandoutSectionSchema, InstructionSectionSchema, InstructionStepSchema, JudgeCriterionSchema, LAYER_IDLE_BUDGET_MS, LAYER_TOTAL_BUDGET_MS, LESSON_PLAN_TEMPLATE, LLMJudgeEngine, LabTierTaskSchema, LearningObjectiveInputSchema, LearningObjectiveRowSchema, LessonFlowPhaseSchema, LessonPlan5ESchema, LessonPlanEDPSchema, LessonPlanSchema, LessonSectionSchema, LocalWorkspaceManager, MappingKindSchema, MarpSlideSchema, MediaError, MediaLedger, MentorCheatsheetSchema, MilestoneInputSchema, MisconceptionEvaluator, MisconceptionSchema, ModelPolicyResolver, NVIDIA_MODELS, NodeKindSchema, OrganizerTypeEnum, PROJECT_INSTRUCTION_TEMPLATE, PhaseInputSchema, PlanConstraintsSchema, PlannerInputSchema, PlanningGraphSchema, PlanningNodeSchema, PrerequisiteDecisionEntrySchema, PrerequisiteDecisionSchema, ProductGoalSchema, ProgressiveHintsSchema, ProjectGraphSchema, ProjectInstructionSchema, ProjectProfileSchema, QUIZ_TEMPLATE, QualityAuditVerdictSchema, QuizOptionSchema, REVIEW_GAME_TEMPLATE, RUBRIC_TEMPLATE, RecordProvenanceSchema, ResourceMapRowSchema, ReviewGameExportRowSchema, ReviewGameQuestionSchema, ReviewGameSchema, RoadmapInputSchema, RotationStationSchema, RubricCriteriaSchema, RubricSchema, SCIENCE_LAB_TEMPLATE, SELF_LAB_TEMPLATE, SLIDE_CANONICAL_METHODOLOGY, SLIDE_LAYOUT_PRESETS, SLIDE_TEMPLATE, STANDARD_REF_REGEX, STANDARD_SOT_FILES, STATION_ROTATION_TEMPLATE, ScaffoldDecisionEntrySchema, ScaffoldDecisionSchema, ScienceLabSchema, ScoringRubricRowSchema, SelfLabSchema, SelfPacedBundleSchema, SelfPacedChallengeSchema, SessionPlanSchema, SilverTierSchema, SlideBlueprintArraySchema, SlideBlueprintItemSchema, SlideDeckSchema, StandardizedTermRowSchema, StandardsRegistryAdapter, StationRecordRowSchema, StationRotationSchema, StationTypeEnum, SupabaseCurriculumAdapter, TASK_CARDS_TEMPLATE, TEACHER_GUIDE_TEMPLATE, TIERED_PRACTICE_TEMPLATE, TaskCardSchema, TaskCardsSchema, TeacherGuideSchema, TeachingScriptPhaseSchema, TierLevelEnum, TierObjectiveSchema, TieredPracticeSchema, TranslationPolicySchema, TroubleshootingEntrySchema, TroubleshootingRowSchema, UnitPlanSchema, UserJourneySchema, WORKSHEET_TEMPLATE, WorksheetItemSchema, WorksheetItemTypeEnum, WorksheetPartSchema, WorksheetSchema, activityTools, analystTools, analyzeProjectCreationIntent, assertAcyclic, assessorTools, auditCurriculumQualityFlow, auditQualityReport, buildActivityPrompt, buildCodeLabPrompt, buildCurriculumContext, buildCurriculumPlan, buildDeliveryPackages, buildDiagnosticQuizPrompt, buildDomainLexiconGuardrail, buildExpositionContext, buildExpositionExcerpt, buildExtensionPrompt, buildHandoutPrompt, buildHeadingDirective, buildHtmlDeckSlidePrompt, buildImagePrompt, buildJudgePrompt, buildLanguageDirective, buildLessonExcerpt, buildLessonMasterPrompt, buildMarpMarkdownSlidePrompt, buildProjectInstructionPrompt, buildSectionAwareExcerpt, buildSelfLabPrompt, buildSessionSliceContext, buildSlidesPrompt, buildStandardStackMarkdown, buildStandardsContext, buildStandardsContextBlock, buildTeacherGuidePrompt, buildWorksheetPrompt, closeTruncatedJson, computeContentHash, computePackingSpec, conductPreliminaryResearch, contentTools, convertRoadmapToFoundationSot, createAiInferenceError, createContextMissingError, createCurriculumStorage, createIdleAbortController, createStreamAbortController, createStreamAbortSignal, createStreamChunkExtractor, curateMediaLedger, designerTools, detectProjectPedagogy, ensureExpositionForLesson, ensureKnowledgeExposition, evaluateStandardsCoverage, executeCurriculumCommand, executeSlideProductionWorkflow, exportAllProjectQuizzes, expositionCacheKey, extractScopeSequenceRows, extractSectionHeadingsFromSLC, extractSessionSlice, extractStandardRefs, extractStreamChunk, extractSymbolLedger, extractThoughtAndContent, findStandardStatement, formatQuizzesToCsv, fulfillMediaLedger, gateModeFor, generateActivityFlow, generateCodeLabFlow, generateDiagnosticQuizFlow, generateEducationalImage, generateExtensionFlow, generateHandoutFlow, generateLessonMasterFlow, generateMilestoneCurriculumBundle, generatePhase1SotArtifacts, generatePhase2SotArtifacts, generateProjectInstruction, generateProjectInstructionFlow, generateRoadmapCurriculum, generateSelfLabFlow, generateSelfPacedBundle, generateSingleArtifact, generateSlidesFlow, generateTeacherGuideFlow, generateWorksheetFlow, getAIModel, getArtifactMetadata, getDesignatedFallbackChain, getDesignatedFallbackConfig, getLessonMetadata, getProjectArtifactScope, getProjectStatusReport, getSlideLayoutPresetById, getSlideLayoutPresetsByCategory, getSmartResumeContext, glossaryTermsForSession, illustratorTools, importRoadmapToProject, ingestProjectGraphIntoProject, initializeProjectInStorage, injectMediaIntoMarkdown, isExpositionFresh, isModelAllowed, isProviderEnabled, isTranslationDue, lintAndSanitizeArtifact, lintCurriculumFramework, lintFrameworkPack, loadCurriculumTemplate, loadSotTemplate, normalizePlanningGraph, normalizeSlcContract, packagerTools, parseGateSettings, parseQuizMarkdown, parseRoadmapJsonToProjectPayload, produceBatchLessons, produceSingleLesson, publishToGitHub, publishToSupabase, rankGenCandidates, renderFrameworkFromPlan, renderMediaPlaceholder, researcherTools, resolveGateSettings, resolveStandardsPacks, resolveStreamBudget, resolveTargetLanguageCode, resolveTranslationTargets, reviewerTools, runCurriculumAIInference, safeParseJson, searchEducationalImages, searchEducationalVideos, selectStatementsForLesson, serializeActivityToMarkdown, serializeCodeLabToMarkdown, serializeDiagnosticQuizToMarkdown, serializeHandoutToMarkdown, serializeLessonToMarkdown, serializeProjectInstructionToMarkdown, serializeSelfLabToMarkdown, slugifyProjectName, streamCurriculumAIInference, streamCurriculumAIInferenceWithTools, streamDiagnosticQuizFlow, streamLLMWithFallback, streamLayerPrefillWithFallback, streamLessonMasterFlow, streamSelfLabFlow, stripLlmJsonWrappers, targetLanguageDisplayName, techSmeTools, topoSort, uploadAssetToBucket, validateArtifactDependencies, validateCurriculumPlan, validateFrameworkPack, validateMarkdownTables, validateMermaidSyntax, withAutoRepair };
|
|
31795
|
+
export { ACT_TEMPLATE, ARTIFACT_DEPENDENCY_ROUTING, ARTIFACT_EXECUTION_ORDER, AcademicAuditor, ActiveLearningWorkflowSchema, ActivityLabSchema, ActivitySeqRowSchema, ActivityStepSchema, ArtifactContractRowSchema, AssessmentMapRowSchema, AssessmentObjectiveSchema, BELL_RINGER_TEMPLATE, BLOOM_ACTION_VERBS, BOM_TEMPLATE, BUNDLED_STANDARDS_PACK_IDS, BellRingerDaySchema, BellRingerSchema, BloomHintSchema, BloomLevelSchema, BloomTaxonomyEvaluator, BronzeTierSchema, CERConclusionSchema, CHOICE_BOARD_TEMPLATE, CODE_LAB_TEMPLATE, CURRICULUM_SLASH_COMMANDS, CardTierEnum, ChoiceBoardRubricRowSchema, ChoiceBoardSchema, ChoiceRuleSchema, ChoiceSquareSchema, ClassificationSchema, CodeHardwareFeasibilityEvaluator, CodeLabSchema, CodeSnippetSchema, CompetencyRubricRowSchema, ComputationalThinkingSchema, ConstructiveAlignmentEvaluator, CoreConceptSchema, CourseObjectiveSchema, CoverageReportSchema, CrossArtifactDriftEvaluator, CurriculumArtifactSchema, CurriculumError, CurriculumPlanSchema, CurriculumQualityReportSchema, DEFAULT_ARTIFACT_STREAM_IDLE_MS, DEFAULT_ARTIFACT_STREAM_TOTAL_MS, DEFAULT_ENABLED_PROVIDERS, DEFAULT_GATE_SETTINGS, DEFAULT_KX_PRIORITIES, DEFAULT_LESSON_PRIORITIES, DEFAULT_STREAM_IDLE_MS, DEFAULT_STREAM_TOTAL_MS, DEFAULT_VIETNAMESE_SECTION_HEADINGS, DependencyEdgeSchema, DepthAssignmentSchema, DepthLevelSchema, DeterministicPipelineRunner, DeterministicStructuralLinter, DiagnosticQuestionSchema, DiagnosticQuizSchema, EDPPhaseEnum, EXIT_TICKET_TEMPLATE, EXPOSITION_REL, EXT_TEMPLATE, EntryLevelSchema, ExitTicketBugHuntSchema, ExitTicketMetacognitionSchema, ExitTicketQuickItemSchema, ExitTicketRecallPromptSchema, ExitTicketSchema, ExperimentalDesignSchema, ExpositionApprovalError, ExtensionChallengeSchema, ExtensionSchema, FileSystemCurriculumAdapter, FiveEFlowPhaseSchema, FiveEInstructionalEvaluator, FiveEPhaseEnum, FrameworkMappingSchema, FrameworkPackManifestSchema, FrameworkPackSchema, FrameworkStatementSchema, GLOSSARY_TEMPLATE, GRAPHIC_ORGANIZER_TEMPLATE, GeneratedSlideArraySchema, GeneratedSlideSchema, GlossaryQuickRefRowSchema, GlossarySchema, GlossaryTermSchema, GoldTierSchema, GradeBandSchema, GraphicOrganizerItemSchema, GraphicOrganizerSchema, HANDOUT_TEMPLATE, HandoutSchema, HandoutSectionSchema, HybridBlueprintArraySchema, HybridBlueprintItemSchema, HybridDeckSlideArraySchema, HybridDeckSlideSchema, HybridPipelineError, InstructionSectionSchema, InstructionStepSchema, JudgeCriterionSchema, LAYER_IDLE_BUDGET_MS, LAYER_TOTAL_BUDGET_MS, LESSON_PLAN_TEMPLATE, LLMJudgeEngine, LabTierTaskSchema, LearningObjectiveInputSchema, LearningObjectiveRowSchema, LessonFlowPhaseSchema, LessonPlan5ESchema, LessonPlanEDPSchema, LessonPlanSchema, LessonSectionSchema, LocalWorkspaceManager, MappingKindSchema, MarpSlideSchema, MediaError, MediaLedger, MentorCheatsheetSchema, MilestoneInputSchema, MisconceptionEvaluator, MisconceptionSchema, ModelPolicyResolver, NVIDIA_MODELS, NodeKindSchema, OrganizerTypeEnum, PROJECT_INSTRUCTION_TEMPLATE, PhaseInputSchema, PlanConstraintsSchema, PlannerInputSchema, PlanningGraphSchema, PlanningNodeSchema, PrerequisiteDecisionEntrySchema, PrerequisiteDecisionSchema, ProductGoalSchema, ProgressiveHintsSchema, ProjectGraphSchema, ProjectInstructionSchema, ProjectProfileSchema, QUIZ_TEMPLATE, QualityAuditVerdictSchema, QuizOptionSchema, REVIEW_GAME_TEMPLATE, RUBRIC_TEMPLATE, RecordProvenanceSchema, ResourceMapRowSchema, ReviewGameExportRowSchema, ReviewGameQuestionSchema, ReviewGameSchema, RoadmapInputSchema, RotationStationSchema, RubricCriteriaSchema, RubricSchema, SATELLITE_LESSON_PRIORITIES, SCIENCE_LAB_TEMPLATE, SELF_LAB_TEMPLATE, SLIDE_CANONICAL_METHODOLOGY, SLIDE_LAYOUT_PRESETS, SLIDE_TEMPLATE, STANDARD_REF_REGEX, STANDARD_SOT_FILES, STATION_ROTATION_TEMPLATE, ScaffoldDecisionEntrySchema, ScaffoldDecisionSchema, ScienceLabSchema, ScoringRubricRowSchema, SelfLabSchema, SelfPacedBundleSchema, SelfPacedChallengeSchema, SessionPlanSchema, SilverTierSchema, SlideBlueprintArraySchema, SlideBlueprintItemSchema, SlideDeckSchema, StandardizedTermRowSchema, StandardsRegistryAdapter, StationRecordRowSchema, StationRotationSchema, StationTypeEnum, SupabaseCurriculumAdapter, TASK_CARDS_TEMPLATE, TEACHER_GUIDE_TEMPLATE, TIERED_PRACTICE_TEMPLATE, TaskCardSchema, TaskCardsSchema, TeacherGuideSchema, TeachingScriptPhaseSchema, TierLevelEnum, TierObjectiveSchema, TieredPracticeSchema, TranslationPolicySchema, TroubleshootingEntrySchema, TroubleshootingRowSchema, UnitPlanSchema, UserJourneySchema, WORKSHEET_TEMPLATE, WorksheetItemSchema, WorksheetItemTypeEnum, WorksheetPartSchema, WorksheetSchema, activityTools, analystTools, analyzeProjectCreationIntent, assertAcyclic, assessorTools, atomicWriteFileSync, auditCurriculumQualityFlow, auditQualityReport, buildActivityPrompt, buildCodeLabPrompt, buildCurriculumContext, buildCurriculumPlan, buildDeliveryPackages, buildDiagnosticQuizPrompt, buildDomainLexiconGuardrail, buildExpositionContext, buildExpositionExcerpt, buildExtensionPrompt, buildHandoutPrompt, buildHeadingDirective, buildHtmlDeckSlidePrompt, buildImagePrompt, buildJudgePrompt, buildLanguageDirective, buildLessonExcerpt, buildLessonMasterPrompt, buildMarpMarkdownSlidePrompt, buildProjectInstructionPrompt, buildSectionAwareExcerpt, buildSelfLabPrompt, buildSessionSliceContext, buildSlidesPrompt, buildStandardStackMarkdown, buildStandardsContext, buildStandardsContextBlock, buildTeacherGuidePrompt, buildWorksheetPrompt, closeTruncatedJson, computeContentHash, computePackingSpec, conductPreliminaryResearch, contentTools, convertRoadmapToFoundationSot, createAiInferenceError, createContextMissingError, createCurriculumStorage, createIdleAbortController, createStreamAbortController, createStreamAbortSignal, createStreamChunkExtractor, curateMediaLedger, designerTools, detectProjectPedagogy, emitUsage, ensureExpositionForLesson, ensureKnowledgeExposition, evaluateStandardsCoverage, executeCurriculumCommand, executeSlideProductionWorkflow, exportAllProjectQuizzes, expositionCacheKey, extractCurriculumHorizon, extractJsonArray, extractScopeSequenceRows, extractSectionHeadingsFromSLC, extractSessionSlice, extractStandardRefs, extractStreamChunk, extractSymbolLedger, extractThoughtAndContent, findStandardStatement, formatQuizzesToCsv, fulfillMediaLedger, gateModeFor, generateActivityFlow, generateCodeLabFlow, generateDiagnosticQuizFlow, generateEducationalImage, generateExtensionFlow, generateHandoutFlow, generateLessonMasterFlow, generateMilestoneCurriculumBundle, generatePhase1SotArtifacts, generatePhase2SotArtifacts, generateProjectInstruction, generateProjectInstructionFlow, generateRoadmapCurriculum, generateSelfLabFlow, generateSelfPacedBundle, generateSingleArtifact, generateSlidesFlow, generateTeacherGuideFlow, generateWorksheetFlow, getAIModel, getArtifactMetadata, getDesignatedFallbackChain, getDesignatedFallbackConfig, getLessonMetadata, getProjectArtifactScope, getProjectStatusReport, getSlideLayoutPresetById, getSlideLayoutPresetsByCategory, getSmartResumeContext, glossaryTermsForSession, illustratorTools, importRoadmapToProject, ingestProjectGraphIntoProject, initializeProjectInStorage, injectMediaIntoMarkdown, isExpositionFresh, isModelAllowed, isProviderEnabled, isTranslationDue, lintAndSanitizeArtifact, lintCurriculumFramework, lintFrameworkPack, loadCurriculumTemplate, loadSotTemplate, normalizePlanningGraph, normalizeSlcContract, packagerTools, parseAllSessions, parseGateSettings, parseQuizMarkdown, parseRoadmapJsonToProjectPayload, produceBatchLessons, produceSingleLesson, publishToGitHub, publishToSupabase, rankGenCandidates, renderFrameworkFromPlan, renderHorizonPromptBlock, renderMediaPlaceholder, researcherTools, resolveGateSettings, resolveStandardsPacks, resolveStreamBudget, resolveTargetLanguageCode, resolveTranslationTargets, reviewerTools, runCurriculumAIInference, safeParseJson, searchEducationalImages, searchEducationalVideos, selectStatementsForLesson, serializeActivityToMarkdown, serializeCodeLabToMarkdown, serializeDiagnosticQuizToMarkdown, serializeHandoutToMarkdown, serializeLessonToMarkdown, serializeProjectInstructionToMarkdown, serializeSelfLabToMarkdown, slugifyProjectName, streamCurriculumAIInference, streamCurriculumAIInferenceWithTools, streamDiagnosticQuizFlow, streamLLMWithFallback, streamLayerPrefillWithFallback, streamLessonMasterFlow, streamSelfLabFlow, stripLlmJsonWrappers, targetLanguageDisplayName, techSmeTools, topoSort, uploadAssetToBucket, validateArtifactDependencies, validateCurriculumPlan, validateFrameworkPack, validateHorizonCompliance, validateHybridDeckSlides, validateMarkdownTables, validateMermaidSyntax, withAutoRepair };
|
|
31119
31796
|
//# sourceMappingURL=index.mjs.map
|
|
31120
31797
|
//# sourceMappingURL=index.mjs.map
|