@thanh01.pmt/curriculum-kit 1.4.17 → 1.4.20
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 +876 -141
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +253 -112
- package/dist/index.d.ts +253 -112
- package/dist/index.mjs +870 -143
- package/dist/index.mjs.map +1 -1
- package/dist/workflow/index.cjs +359 -1
- 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 +359 -1
- 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';
|
|
@@ -1585,10 +1585,91 @@ var slideProductionWorkflow_exports = {};
|
|
|
1585
1585
|
__export(slideProductionWorkflow_exports, {
|
|
1586
1586
|
GeneratedSlideArraySchema: () => GeneratedSlideArraySchema,
|
|
1587
1587
|
GeneratedSlideSchema: () => GeneratedSlideSchema,
|
|
1588
|
+
HybridBlueprintArraySchema: () => HybridBlueprintArraySchema,
|
|
1589
|
+
HybridBlueprintItemSchema: () => HybridBlueprintItemSchema,
|
|
1590
|
+
HybridDeckSlideArraySchema: () => HybridDeckSlideArraySchema,
|
|
1591
|
+
HybridDeckSlideSchema: () => HybridDeckSlideSchema,
|
|
1592
|
+
HybridPipelineError: () => HybridPipelineError,
|
|
1588
1593
|
SlideBlueprintArraySchema: () => SlideBlueprintArraySchema,
|
|
1589
1594
|
SlideBlueprintItemSchema: () => SlideBlueprintItemSchema,
|
|
1590
|
-
executeSlideProductionWorkflow: () => executeSlideProductionWorkflow
|
|
1595
|
+
executeSlideProductionWorkflow: () => executeSlideProductionWorkflow,
|
|
1596
|
+
extractJsonArray: () => extractJsonArray,
|
|
1597
|
+
validateHybridDeckSlides: () => validateHybridDeckSlides
|
|
1591
1598
|
});
|
|
1599
|
+
function extractJsonArray(raw) {
|
|
1600
|
+
if (!raw) return { error: "empty response" };
|
|
1601
|
+
let text = raw.replace(/<think>[\s\S]*?<\/think>/gi, "").trim();
|
|
1602
|
+
text = text.replace(/^```(?:json)?\s*/m, "").replace(/```\s*$/m, "").trim();
|
|
1603
|
+
const start = text.indexOf("[");
|
|
1604
|
+
const end = text.lastIndexOf("]");
|
|
1605
|
+
if (start < 0 || end <= start) {
|
|
1606
|
+
return {
|
|
1607
|
+
error: "no JSON array span found",
|
|
1608
|
+
head: text.slice(0, 300),
|
|
1609
|
+
tail: text.slice(-300)
|
|
1610
|
+
};
|
|
1611
|
+
}
|
|
1612
|
+
const span = text.slice(start, end + 1);
|
|
1613
|
+
try {
|
|
1614
|
+
return { value: JSON.parse(span) };
|
|
1615
|
+
} catch {
|
|
1616
|
+
}
|
|
1617
|
+
try {
|
|
1618
|
+
return { value: JSON.parse(jsonrepair(span)) };
|
|
1619
|
+
} catch (e) {
|
|
1620
|
+
return {
|
|
1621
|
+
error: "JSON.parse/jsonrepair failed: " + String(e?.message || e).slice(0, 120),
|
|
1622
|
+
head: text.slice(0, 300),
|
|
1623
|
+
tail: text.slice(-300)
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
function validateHybridDeckSlides(slides, blueprint) {
|
|
1628
|
+
const v = [];
|
|
1629
|
+
if (blueprint.length > 0 && slides.length !== blueprint.length) {
|
|
1630
|
+
v.push(`slide count mismatch: got ${slides.length}, blueprint requires ${blueprint.length}`);
|
|
1631
|
+
}
|
|
1632
|
+
slides.forEach((s, i) => {
|
|
1633
|
+
const n = i + 1;
|
|
1634
|
+
const title = typeof s?.title === "string" ? s.title : "";
|
|
1635
|
+
if (!title.trim()) v.push(`slide ${n}: missing/empty title`);
|
|
1636
|
+
else if (title.length > 150) v.push(`slide ${n}: title too long (${title.length} chars, max 150) \u2014 repetition-loop guard`);
|
|
1637
|
+
const notes = typeof s?.notes === "string" ? s.notes.trim() : "";
|
|
1638
|
+
if (notes.length < 80) v.push(`slide ${n}: presenter notes missing or too short (${notes.length} chars, min 80)`);
|
|
1639
|
+
const code = s?.slots?.code;
|
|
1640
|
+
if (typeof code === "string") {
|
|
1641
|
+
if (code.length > 6e3) v.push(`slide ${n}: code block too long (${code.length} chars, max 6000)`);
|
|
1642
|
+
if (/\/\/\s*TODO|<CODE>|your code here/i.test(code)) v.push(`slide ${n}: placeholder code detected (TODO/<CODE>)`);
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
return v.slice(0, 10);
|
|
1646
|
+
}
|
|
1647
|
+
async function inferTextJson(schema, systemPrompt, userPrompt, options, label) {
|
|
1648
|
+
const model = getAIModel(options.modelOptions);
|
|
1649
|
+
try {
|
|
1650
|
+
const { text, finishReason } = await generateText({
|
|
1651
|
+
model,
|
|
1652
|
+
system: systemPrompt || void 0,
|
|
1653
|
+
prompt: userPrompt,
|
|
1654
|
+
maxOutputTokens: options.maxOutputTokens ?? 65536
|
|
1655
|
+
});
|
|
1656
|
+
const extracted = extractJsonArray(text);
|
|
1657
|
+
if (!("value" in extracted) || extracted.value === void 0) {
|
|
1658
|
+
console.warn(
|
|
1659
|
+
`[SlideProductionWorkflow] ${label}: JSON extraction failed (${extracted.error}); finish=${finishReason}`,
|
|
1660
|
+
extracted.head ? `head=${String(extracted.head).slice(0, 150)}` : ""
|
|
1661
|
+
);
|
|
1662
|
+
return null;
|
|
1663
|
+
}
|
|
1664
|
+
const validated = schema.safeParse(extracted.value);
|
|
1665
|
+
if (validated.success) return validated.data;
|
|
1666
|
+
console.warn(`[SlideProductionWorkflow] ${label}: output failed schema validation:`, validated.error?.message);
|
|
1667
|
+
return null;
|
|
1668
|
+
} catch (err) {
|
|
1669
|
+
console.warn(`[SlideProductionWorkflow] ${label}: generateText failed:`, err?.message || err);
|
|
1670
|
+
return null;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1592
1673
|
async function inferStructured(schema, systemPrompt, userPrompt, options, label) {
|
|
1593
1674
|
try {
|
|
1594
1675
|
const model = getAIModel(options.modelOptions);
|
|
@@ -1630,9 +1711,142 @@ async function inferStructured(schema, systemPrompt, userPrompt, options, label)
|
|
|
1630
1711
|
return null;
|
|
1631
1712
|
}
|
|
1632
1713
|
}
|
|
1714
|
+
function normalizeBlueprintItems(items) {
|
|
1715
|
+
return items.sort((a, b) => (a.slideIndex ?? 0) - (b.slideIndex ?? 0)).map((item, idx) => ({
|
|
1716
|
+
slideIndex: idx + 1,
|
|
1717
|
+
clusterId: item.clusterId ?? Math.floor(idx / 5) + 1,
|
|
1718
|
+
clusterTitle: item.clusterTitle || "Cluster",
|
|
1719
|
+
lessonPhase: item.lessonPhase || "Content",
|
|
1720
|
+
layoutId: item.layoutId,
|
|
1721
|
+
title: item.title,
|
|
1722
|
+
pedagogicalGoal: item.pedagogicalGoal || "",
|
|
1723
|
+
contentFocus: item.contentFocus || [],
|
|
1724
|
+
codeSnippetIntent: item.codeSnippetIntent ?? void 0,
|
|
1725
|
+
visualIntent: item.visualIntent ?? void 0
|
|
1726
|
+
}));
|
|
1727
|
+
}
|
|
1728
|
+
function buildHybridDeckPrompts(params) {
|
|
1729
|
+
const { lessonFlow, blueprint, skillPrompt, language, languageDirective, headingDirective } = params;
|
|
1730
|
+
const blueprintText = JSON.stringify(
|
|
1731
|
+
blueprint.map((s) => ({
|
|
1732
|
+
slideIndex: s.slideIndex,
|
|
1733
|
+
lessonPhase: s.lessonPhase,
|
|
1734
|
+
layoutId: s.layoutId,
|
|
1735
|
+
title: s.title,
|
|
1736
|
+
pedagogicalGoal: s.pedagogicalGoal,
|
|
1737
|
+
contentFocus: s.contentFocus,
|
|
1738
|
+
codeSnippetIntent: s.codeSnippetIntent ?? void 0,
|
|
1739
|
+
visualIntent: s.visualIntent ?? void 0
|
|
1740
|
+
})),
|
|
1741
|
+
null,
|
|
1742
|
+
1
|
|
1743
|
+
);
|
|
1744
|
+
const phasesContent = lessonFlow.phases.length > 0 ? lessonFlow.phases.map((p) => `### ${p.phaseName}
|
|
1745
|
+
${p.content}`).join("\n\n") : lessonFlow.rawContent;
|
|
1746
|
+
const systemPrompt = [
|
|
1747
|
+
skillPrompt,
|
|
1748
|
+
languageDirective,
|
|
1749
|
+
headingDirective,
|
|
1750
|
+
`
|
|
1751
|
+
### OPERATIONAL GROUND RULES (FULL-DECK AUTHORING):
|
|
1752
|
+
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.
|
|
1753
|
+
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>".
|
|
1754
|
+
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).
|
|
1755
|
+
4. Titles must be < 100 characters \u2014 never repeat or loop text.
|
|
1756
|
+
5. Output ONLY the JSON array. No prose, no markdown fences.
|
|
1757
|
+
`.trim()
|
|
1758
|
+
].filter(Boolean).join("\n\n");
|
|
1759
|
+
const userPrompt = `
|
|
1760
|
+
### BLUEPRINT (${blueprint.length} slides \u2014 AUTHOR ALL OF THEM, in this exact order):
|
|
1761
|
+
${blueprintText}
|
|
1762
|
+
|
|
1763
|
+
### LESSON GROUND TRUTH:
|
|
1764
|
+
- Lesson Title: "${lessonFlow.lessonTitle}"
|
|
1765
|
+
- Target Duration: ${lessonFlow.estimatedDuration}
|
|
1766
|
+
- Pedagogy: "${lessonFlow.pedagogicalModel.toUpperCase()}"
|
|
1767
|
+
- Language: "${language}"
|
|
1768
|
+
|
|
1769
|
+
### LESSON PHASE CONTENT (SOURCE OF TRUTH FOR REAL CONTENT):
|
|
1770
|
+
${phasesContent.slice(0, 16e3)}
|
|
1771
|
+
|
|
1772
|
+
---
|
|
1773
|
+
|
|
1774
|
+
### OUTPUT:
|
|
1775
|
+
A single JSON array of exactly ${blueprint.length} slide objects:
|
|
1776
|
+
\`\`\`json
|
|
1777
|
+
[
|
|
1778
|
+
{
|
|
1779
|
+
"id": "slide-1",
|
|
1780
|
+
"layoutId": "${blueprint[0]?.layoutId || "split-concept-code"}",
|
|
1781
|
+
"title": "${blueprint[0]?.title || "Slide Title"}",
|
|
1782
|
+
"slots": { "...layout-specific slots with REAL content..." },
|
|
1783
|
+
"notes": "SCRIPT: ...\\nCOLD CALL: ...\\nSCAFFOLDING: ..."
|
|
1784
|
+
}
|
|
1785
|
+
]
|
|
1786
|
+
\`\`\`
|
|
1787
|
+
`.trim();
|
|
1788
|
+
return { systemPrompt, userPrompt };
|
|
1789
|
+
}
|
|
1790
|
+
async function runHybridPipeline(ctx) {
|
|
1791
|
+
const { lessonFlow, blueprintPrompt, skillPrompt, language, languageDirective, headingDirective, maxRetries, options, onProgress } = ctx;
|
|
1792
|
+
let blueprint = null;
|
|
1793
|
+
for (let attempt = 1; attempt <= maxRetries && !blueprint; attempt++) {
|
|
1794
|
+
onProgress?.("@illustrator", `[1/4] L\u1EADp D\xE0n \xFD Slides \u2014 hybrid blueprint (l\u1EA7n ${attempt}/${maxRetries})...`);
|
|
1795
|
+
const parsed = await inferTextJson(HybridBlueprintArraySchema, "", blueprintPrompt, options, `hybrid-blueprint#${attempt}`);
|
|
1796
|
+
if (parsed && parsed.length > 0) {
|
|
1797
|
+
blueprint = normalizeBlueprintItems(parsed);
|
|
1798
|
+
} else if (attempt < maxRetries) {
|
|
1799
|
+
onProgress?.("@illustrator", `\u26A0\uFE0F Hybrid blueprint l\u1EA7n ${attempt}/${maxRetries} l\u1ED7i \u2014 th\u1EED l\u1EA1i...`, { type: "warning" });
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
if (!blueprint || blueprint.length === 0) {
|
|
1803
|
+
throw new HybridPipelineError(`blueprint failed after ${maxRetries} attempts`);
|
|
1804
|
+
}
|
|
1805
|
+
onProgress?.("@illustrator", `[1/4] D\xE0n \xFD ${blueprint.length} slides ho\xE0n t\u1EA5t \u2014 chuy\u1EC3n sang authoring to\xE0n deck...`);
|
|
1806
|
+
const { systemPrompt, userPrompt } = buildHybridDeckPrompts({
|
|
1807
|
+
lessonFlow,
|
|
1808
|
+
blueprint,
|
|
1809
|
+
skillPrompt,
|
|
1810
|
+
language,
|
|
1811
|
+
languageDirective,
|
|
1812
|
+
headingDirective
|
|
1813
|
+
});
|
|
1814
|
+
let slides = null;
|
|
1815
|
+
let lastViolations = [];
|
|
1816
|
+
for (let attempt = 1; attempt <= maxRetries && !slides; attempt++) {
|
|
1817
|
+
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})...`);
|
|
1818
|
+
const feedback = attempt > 1 && lastViolations.length > 0 ? `
|
|
1819
|
+
|
|
1820
|
+
### \u26A0\uFE0F PREVIOUS ATTEMPT REJECTED \u2014 fix these violations:
|
|
1821
|
+
${lastViolations.map((x) => "- " + x).join("\n")}
|
|
1822
|
+
Return exactly ${blueprint.length} slides, same order as the blueprint.` : "";
|
|
1823
|
+
const parsed = await inferTextJson(HybridDeckSlideArraySchema, systemPrompt, userPrompt + feedback, options, `hybrid-author#${attempt}`);
|
|
1824
|
+
if (!parsed || parsed.length === 0) {
|
|
1825
|
+
lastViolations = ["Output missing, empty, or not a valid JSON array of slide objects"];
|
|
1826
|
+
} else {
|
|
1827
|
+
const violations = validateHybridDeckSlides(parsed, blueprint);
|
|
1828
|
+
if (violations.length === 0) {
|
|
1829
|
+
slides = parsed;
|
|
1830
|
+
break;
|
|
1831
|
+
}
|
|
1832
|
+
lastViolations = violations;
|
|
1833
|
+
}
|
|
1834
|
+
if (attempt < maxRetries) {
|
|
1835
|
+
onProgress?.("@illustrator", `\u26A0\uFE0F Deck authoring l\u1EA7n ${attempt}/${maxRetries} vi ph\u1EA1m guardrails \u2014 retry v\u1EDBi corrective feedback...`, {
|
|
1836
|
+
type: "warning",
|
|
1837
|
+
violations: lastViolations
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
if (!slides) {
|
|
1842
|
+
throw new HybridPipelineError(
|
|
1843
|
+
`deck authoring failed after ${maxRetries} attempts. Last violations: ${lastViolations.slice(0, 3).join("; ")}`
|
|
1844
|
+
);
|
|
1845
|
+
}
|
|
1846
|
+
return { slides, blueprint };
|
|
1847
|
+
}
|
|
1633
1848
|
async function executeSlideProductionWorkflow(options) {
|
|
1634
1849
|
const {
|
|
1635
|
-
lessonMarkdown,
|
|
1636
1850
|
lessonCode,
|
|
1637
1851
|
lessonTitle,
|
|
1638
1852
|
targetSlideCount,
|
|
@@ -1643,6 +1857,7 @@ async function executeSlideProductionWorkflow(options) {
|
|
|
1643
1857
|
maxRetries = 3,
|
|
1644
1858
|
onProgress
|
|
1645
1859
|
} = options;
|
|
1860
|
+
const engineRequested = options.engine ?? "hybrid";
|
|
1646
1861
|
let presentationKitSkills = null;
|
|
1647
1862
|
let presentationKitCore = null;
|
|
1648
1863
|
try {
|
|
@@ -1653,117 +1868,140 @@ async function executeSlideProductionWorkflow(options) {
|
|
|
1653
1868
|
presentationKitCore = await import('@thanh01.pmt/presentation-kit');
|
|
1654
1869
|
} catch {
|
|
1655
1870
|
}
|
|
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);
|
|
1871
|
+
const lessonFlow = parseLessonFlow(options.lessonMarkdown);
|
|
1659
1872
|
const getStylePreset = presentationKitSkills?.getStylePreset;
|
|
1660
1873
|
const stylePreset = getStylePreset ? getStylePreset(stylePresetId) : { name: "Blue Professional" };
|
|
1874
|
+
const skillPrompt = presentationKitSkills?.getFrontendSlidesSkillPrompt ? presentationKitSkills.getFrontendSlidesSkillPrompt({ stylePresetId }) : "";
|
|
1661
1875
|
const blueprintPrompt = buildSlideBlueprintPrompt({
|
|
1662
1876
|
lessonFlow,
|
|
1663
1877
|
targetSlideCount,
|
|
1664
1878
|
stylePresetName: stylePreset?.name || "Blue Professional"
|
|
1665
1879
|
});
|
|
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
|
-
|
|
1880
|
+
let blueprintItems;
|
|
1881
|
+
let allGeneratedSlides;
|
|
1882
|
+
let engineUsed = engineRequested;
|
|
1883
|
+
const hybridResult = engineRequested === "hybrid" ? await runHybridPipeline({
|
|
1884
|
+
lessonFlow,
|
|
1885
|
+
blueprintPrompt,
|
|
1886
|
+
skillPrompt,
|
|
1887
|
+
language,
|
|
1888
|
+
languageDirective,
|
|
1889
|
+
headingDirective,
|
|
1890
|
+
maxRetries,
|
|
1891
|
+
options,
|
|
1892
|
+
onProgress
|
|
1893
|
+
}).catch((hybridErr) => {
|
|
1894
|
+
console.warn(`[SlideProductionWorkflow] Hybrid engine failed: ${hybridErr?.message || hybridErr} \u2014 falling back to chunked pipeline.`);
|
|
1895
|
+
onProgress?.("@illustrator", `\u26A0\uFE0F Hybrid engine l\u1ED7i \u2014 chuy\u1EC3n sang chunked pipeline (per-cluster)...`, { type: "warning" });
|
|
1896
|
+
return null;
|
|
1897
|
+
}) : null;
|
|
1898
|
+
if (hybridResult) {
|
|
1899
|
+
blueprintItems = hybridResult.blueprint;
|
|
1900
|
+
allGeneratedSlides = hybridResult.slides.map((s, idx) => ({
|
|
1901
|
+
id: s.id || `slide-${idx + 1}`,
|
|
1902
|
+
layoutId: s.layoutId,
|
|
1903
|
+
title: s.title,
|
|
1904
|
+
slots: s.slots || {},
|
|
1905
|
+
notes: s.notes || ""
|
|
1906
|
+
}));
|
|
1907
|
+
} else {
|
|
1908
|
+
engineUsed = "chunked";
|
|
1909
|
+
const countLabel = targetSlideCount ? `${targetSlideCount} ` : "h\u1EEFu c\u01A1 ";
|
|
1910
|
+
onProgress?.("@illustrator", `[1/4] Ph\xE2n t\xEDch m\u1EA1ch b\xE0i gi\u1EA3ng LESSON & L\u1EADp D\xE0n \xFD ${countLabel}Slides...`);
|
|
1911
|
+
blueprintItems = await pRetry(
|
|
1912
|
+
async () => {
|
|
1913
|
+
const items = await inferStructured(
|
|
1914
|
+
SlideBlueprintArraySchema,
|
|
1915
|
+
"",
|
|
1916
|
+
blueprintPrompt,
|
|
1917
|
+
options,
|
|
1918
|
+
"blueprint"
|
|
1919
|
+
);
|
|
1920
|
+
if (!items || items.length === 0) {
|
|
1921
|
+
throw new Error("Blueprint generation returned empty or schema-invalid output");
|
|
1922
|
+
}
|
|
1923
|
+
return normalizeBlueprintItems(items);
|
|
1924
|
+
},
|
|
1925
|
+
{
|
|
1926
|
+
retries: maxRetries - 1,
|
|
1927
|
+
onFailedAttempt: (err) => {
|
|
1928
|
+
onProgress?.("@illustrator", `\u26A0\uFE0F Blueprint attempt ${err.attemptNumber}/${maxRetries} failed \u2014 retrying...`, {
|
|
1929
|
+
type: "warning"
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1694
1932
|
}
|
|
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}
|
|
1933
|
+
);
|
|
1934
|
+
const clustersMap = /* @__PURE__ */ new Map();
|
|
1935
|
+
for (const item of blueprintItems) {
|
|
1936
|
+
const cId = item.clusterId || Math.floor((item.slideIndex - 1) / 5) + 1;
|
|
1937
|
+
if (!clustersMap.has(cId)) clustersMap.set(cId, []);
|
|
1938
|
+
clustersMap.get(cId).push(item);
|
|
1939
|
+
}
|
|
1940
|
+
const clusters = Array.from(clustersMap.entries()).sort(([a], [b]) => a - b);
|
|
1941
|
+
allGeneratedSlides = [];
|
|
1942
|
+
const failedClusters = [];
|
|
1943
|
+
let clusterIdx = 0;
|
|
1944
|
+
for (const [cId, clusterSlides] of clusters) {
|
|
1945
|
+
clusterIdx++;
|
|
1946
|
+
const clusterTitle = clusterSlides[0]?.clusterTitle || `Giai \u0111o\u1EA1n ${clusterIdx}`;
|
|
1947
|
+
onProgress?.("@illustrator", `[2/4] Sinh chi ti\u1EBFt C\u1EE5m ${clusterIdx}/${clusters.length}: "${clusterTitle}" (${clusterSlides.length} slides)...`);
|
|
1948
|
+
const clusterPhaseNames = new Set(clusterSlides.map((s) => s.lessonPhase.toLowerCase()));
|
|
1949
|
+
const matchingPhases = lessonFlow.phases.filter((p) => clusterPhaseNames.has(p.phaseName.toLowerCase()));
|
|
1950
|
+
const lessonExcerpt = matchingPhases.length > 0 ? matchingPhases.map((p) => `### ${p.phaseName}
|
|
1715
1951
|
${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
|
-
|
|
1952
|
+
const { systemPrompt, userPrompt } = buildSlideBatchPrompt({
|
|
1953
|
+
clusterId: cId,
|
|
1954
|
+
clusterTitle,
|
|
1955
|
+
clusterSlides,
|
|
1956
|
+
lessonFlow,
|
|
1957
|
+
lessonExcerpt,
|
|
1958
|
+
skillPrompt,
|
|
1959
|
+
language,
|
|
1960
|
+
languageDirective,
|
|
1961
|
+
headingDirective
|
|
1962
|
+
});
|
|
1963
|
+
try {
|
|
1964
|
+
const batchSlides = await pRetry(
|
|
1965
|
+
async () => {
|
|
1966
|
+
const slides = await inferStructured(
|
|
1967
|
+
GeneratedSlideArraySchema,
|
|
1968
|
+
systemPrompt,
|
|
1969
|
+
userPrompt,
|
|
1970
|
+
options,
|
|
1971
|
+
`cluster-${cId}`
|
|
1972
|
+
);
|
|
1973
|
+
if (!slides || slides.length === 0) {
|
|
1974
|
+
throw new Error(`Cluster ${cId} returned empty or schema-invalid output`);
|
|
1975
|
+
}
|
|
1976
|
+
return slides;
|
|
1977
|
+
},
|
|
1978
|
+
{
|
|
1979
|
+
retries: maxRetries - 1,
|
|
1980
|
+
onFailedAttempt: (err) => {
|
|
1981
|
+
onProgress?.("@illustrator", `\u26A0\uFE0F C\u1EE5m ${clusterIdx} l\u1EA7n ${err.attemptNumber}/${maxRetries} l\u1ED7i \u2014 retry ri\xEAng c\u1EE5m n\xE0y...`, {
|
|
1982
|
+
type: "warning"
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1748
1985
|
}
|
|
1749
|
-
|
|
1986
|
+
);
|
|
1987
|
+
allGeneratedSlides.push(...batchSlides);
|
|
1988
|
+
} catch (clusterErr) {
|
|
1989
|
+
failedClusters.push(cId);
|
|
1990
|
+
console.error(`[SlideProductionWorkflow] Cluster ${cId} permanently failed after ${maxRetries} attempts:`, clusterErr?.message || clusterErr);
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
if (failedClusters.length > 0) {
|
|
1994
|
+
throw new Error(
|
|
1995
|
+
`[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
1996
|
);
|
|
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
1997
|
}
|
|
1756
1998
|
}
|
|
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
1999
|
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
2000
|
const normalizer = presentationKitCore?.normalizeSlideSlots;
|
|
1764
2001
|
const normalizedSlides = allGeneratedSlides.map((s, idx) => {
|
|
1765
2002
|
const base = normalizer ? normalizer(s) : s;
|
|
1766
2003
|
if (!base.id) base.id = `slide-${idx + 1}`;
|
|
2004
|
+
if (!base.slots || typeof base.slots !== "object") base.slots = {};
|
|
1767
2005
|
return base;
|
|
1768
2006
|
});
|
|
1769
2007
|
const deckJson = {
|
|
@@ -1773,16 +2011,19 @@ ${p.content}`).join("\n\n") : lessonFlow.rawContent.slice(0, 3500);
|
|
|
1773
2011
|
slides: normalizedSlides
|
|
1774
2012
|
};
|
|
1775
2013
|
let compiledHtml;
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
} catch (compErr) {
|
|
1784
|
-
console.warn(`[SlideProductionWorkflow] Failed compiling HTML deck:`, compErr?.message || compErr);
|
|
2014
|
+
try {
|
|
2015
|
+
let compiled = null;
|
|
2016
|
+
if (typeof presentationKitCore?.compileHtmlDeckAsync === "function") {
|
|
2017
|
+
compiled = await presentationKitCore.compileHtmlDeckAsync(deckJson);
|
|
2018
|
+
}
|
|
2019
|
+
if (!compiled?.html && typeof presentationKitCore?.compileHtmlDeck === "function") {
|
|
2020
|
+
compiled = presentationKitCore.compileHtmlDeck(deckJson);
|
|
1785
2021
|
}
|
|
2022
|
+
if (compiled?.html) {
|
|
2023
|
+
compiledHtml = compiled.html;
|
|
2024
|
+
}
|
|
2025
|
+
} catch (compErr) {
|
|
2026
|
+
console.warn(`[SlideProductionWorkflow] Failed compiling HTML deck:`, compErr?.message || compErr);
|
|
1786
2027
|
}
|
|
1787
2028
|
const markdownWrapper = `---
|
|
1788
2029
|
id: "SLIDE_${lessonCode}"
|
|
@@ -1806,10 +2047,11 @@ ${JSON.stringify(deckJson, null, 2)}
|
|
|
1806
2047
|
compiledHtml,
|
|
1807
2048
|
markdownWrapper,
|
|
1808
2049
|
blueprint: blueprintItems,
|
|
1809
|
-
slideCount: normalizedSlides.length
|
|
2050
|
+
slideCount: normalizedSlides.length,
|
|
2051
|
+
engine: engineUsed
|
|
1810
2052
|
};
|
|
1811
2053
|
}
|
|
1812
|
-
var SlideBlueprintItemSchema, SlideBlueprintArraySchema, GeneratedSlideSchema, GeneratedSlideArraySchema;
|
|
2054
|
+
var LAYOUT_ID_ENUM, SlideBlueprintItemSchema, SlideBlueprintArraySchema, GeneratedSlideSchema, GeneratedSlideArraySchema, HybridBlueprintItemSchema, HybridBlueprintArraySchema, HybridDeckSlideSchema, HybridDeckSlideArraySchema, HybridPipelineError;
|
|
1813
2055
|
var init_slideProductionWorkflow = __esm({
|
|
1814
2056
|
"src/services/slideProductionWorkflow.ts"() {
|
|
1815
2057
|
init_lessonFlowParser();
|
|
@@ -1817,37 +2059,61 @@ var init_slideProductionWorkflow = __esm({
|
|
|
1817
2059
|
init_slideBatchPrompt();
|
|
1818
2060
|
init_provider_factory();
|
|
1819
2061
|
init_streamRunner();
|
|
2062
|
+
LAYOUT_ID_ENUM = z.enum([
|
|
2063
|
+
"hero-cover",
|
|
2064
|
+
"split-concept-code",
|
|
2065
|
+
"two-columns-compare",
|
|
2066
|
+
"three-cards-grid",
|
|
2067
|
+
"timeline-steps",
|
|
2068
|
+
"metric-callout",
|
|
2069
|
+
"checkpoint-quiz",
|
|
2070
|
+
"tiered-practice-3cards",
|
|
2071
|
+
"summary-takeaways"
|
|
2072
|
+
]);
|
|
1820
2073
|
SlideBlueprintItemSchema = z.object({
|
|
1821
2074
|
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
|
-
]),
|
|
2075
|
+
clusterId: z.number().int().min(1).nullish().default(1),
|
|
2076
|
+
clusterTitle: z.string().nullish().default("Cluster"),
|
|
2077
|
+
lessonPhase: z.string().nullish().default("Content"),
|
|
2078
|
+
layoutId: LAYOUT_ID_ENUM,
|
|
1836
2079
|
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().
|
|
2080
|
+
pedagogicalGoal: z.string().nullish().default(""),
|
|
2081
|
+
contentFocus: z.array(z.string()).nullish().default([]),
|
|
2082
|
+
codeSnippetIntent: z.string().nullish(),
|
|
2083
|
+
visualIntent: z.string().nullish()
|
|
1841
2084
|
});
|
|
1842
2085
|
SlideBlueprintArraySchema = z.array(SlideBlueprintItemSchema);
|
|
1843
2086
|
GeneratedSlideSchema = z.object({
|
|
1844
|
-
id: z.string().
|
|
1845
|
-
layoutId: z.string(),
|
|
2087
|
+
id: z.string().nullish(),
|
|
2088
|
+
layoutId: z.string().min(1),
|
|
1846
2089
|
title: z.string().min(1),
|
|
1847
|
-
slots: z.record(z.any()).default({}),
|
|
1848
|
-
notes: z.string().default("")
|
|
2090
|
+
slots: z.record(z.any()).nullish().default({}),
|
|
2091
|
+
notes: z.string().nullish().default("")
|
|
1849
2092
|
});
|
|
1850
2093
|
GeneratedSlideArraySchema = z.array(GeneratedSlideSchema);
|
|
2094
|
+
HybridBlueprintItemSchema = z.object({
|
|
2095
|
+
slideIndex: z.number().int().min(1),
|
|
2096
|
+
clusterId: z.number().int().min(1).nullish(),
|
|
2097
|
+
clusterTitle: z.string().nullish(),
|
|
2098
|
+
lessonPhase: z.string().nullish(),
|
|
2099
|
+
layoutId: LAYOUT_ID_ENUM,
|
|
2100
|
+
title: z.string().min(1).max(300),
|
|
2101
|
+
pedagogicalGoal: z.string().nullish().default(""),
|
|
2102
|
+
contentFocus: z.array(z.string()).nullish().default([]),
|
|
2103
|
+
codeSnippetIntent: z.string().nullish(),
|
|
2104
|
+
visualIntent: z.string().nullish()
|
|
2105
|
+
});
|
|
2106
|
+
HybridBlueprintArraySchema = z.array(HybridBlueprintItemSchema);
|
|
2107
|
+
HybridDeckSlideSchema = z.object({
|
|
2108
|
+
id: z.string().nullish(),
|
|
2109
|
+
layoutId: z.string().min(1),
|
|
2110
|
+
title: z.string().min(1).max(300),
|
|
2111
|
+
slots: z.record(z.any()).nullish().default({}),
|
|
2112
|
+
notes: z.string().nullish().default("")
|
|
2113
|
+
});
|
|
2114
|
+
HybridDeckSlideArraySchema = z.array(HybridDeckSlideSchema);
|
|
2115
|
+
HybridPipelineError = class extends Error {
|
|
2116
|
+
};
|
|
1851
2117
|
}
|
|
1852
2118
|
});
|
|
1853
2119
|
var LearningObjectiveRowSchema = z.object({
|
|
@@ -10676,8 +10942,310 @@ ${lines.join("\n")}
|
|
|
10676
10942
|
- For example: if canonical section is "Computational Thinking Focus", your heading must be "## [REQUIRED] ${headings["Computational Thinking Focus"] || "Computational Thinking Focus"}".`;
|
|
10677
10943
|
}
|
|
10678
10944
|
|
|
10945
|
+
// src/services/curriculumHorizon.ts
|
|
10946
|
+
init_errors();
|
|
10947
|
+
var DETAILED_BRIDGE_WINDOW = 2;
|
|
10948
|
+
var BOUNDARY_PEEK_WINDOW = 2;
|
|
10949
|
+
function parseAllSessions(plan, frameworkMarkdown) {
|
|
10950
|
+
if (plan) {
|
|
10951
|
+
const rawSessions = Array.isArray(plan.sessions) ? plan.sessions : Array.isArray(plan) ? plan : [];
|
|
10952
|
+
if (rawSessions.length > 0) {
|
|
10953
|
+
return rawSessions.map((s, idx) => ({
|
|
10954
|
+
id: s.id || `L${String(idx + 1).padStart(2, "0")}`,
|
|
10955
|
+
order: typeof s.order === "number" ? s.order : idx + 1,
|
|
10956
|
+
title: s.title || "",
|
|
10957
|
+
prose_objective: s.prose_objective || s.objective || "",
|
|
10958
|
+
new_keywords: Array.isArray(s.new_keywords) ? s.new_keywords : Array.isArray(s.keywords) ? s.keywords : [],
|
|
10959
|
+
prerequisite_keywords: Array.isArray(s.prerequisite_keywords) ? s.prerequisite_keywords : [],
|
|
10960
|
+
depth_assignments: Array.isArray(s.depth_assignments) ? s.depth_assignments : []
|
|
10961
|
+
}));
|
|
10962
|
+
}
|
|
10963
|
+
}
|
|
10964
|
+
if (frameworkMarkdown && typeof frameworkMarkdown === "string") {
|
|
10965
|
+
const lines = frameworkMarkdown.split("\n");
|
|
10966
|
+
let headerCols = [];
|
|
10967
|
+
const sessions = [];
|
|
10968
|
+
for (const line of lines) {
|
|
10969
|
+
const trimmed = line.trim();
|
|
10970
|
+
if (!trimmed.startsWith("|")) continue;
|
|
10971
|
+
const cols = trimmed.split("|").slice(1, -1).map((c) => c.trim());
|
|
10972
|
+
const lower = cols.map((c) => c.toLowerCase());
|
|
10973
|
+
if (lower.some((c) => c.includes("lesson code") || c === "m\xE3 b\xE0i" || c.includes("m\xE3 b\xE0i h\u1ECDc"))) {
|
|
10974
|
+
headerCols = cols;
|
|
10975
|
+
continue;
|
|
10976
|
+
}
|
|
10977
|
+
if (/^[-: |]+$/.test(trimmed.slice(1, -1))) continue;
|
|
10978
|
+
if (cols.length < 3) continue;
|
|
10979
|
+
let lessonCode = "";
|
|
10980
|
+
let title = "";
|
|
10981
|
+
let objective = "";
|
|
10982
|
+
let concept = "";
|
|
10983
|
+
let keywordsStr = "";
|
|
10984
|
+
if (headerCols.length > 0) {
|
|
10985
|
+
const col = (name) => {
|
|
10986
|
+
const idx = headerCols.findIndex((h) => h.toLowerCase().includes(name));
|
|
10987
|
+
return idx >= 0 ? cols[idx] || "" : "";
|
|
10988
|
+
};
|
|
10989
|
+
lessonCode = (col("lesson code") || col("m\xE3 b\xE0i") || cols[1] || "").replace(/\*\*/g, "").trim();
|
|
10990
|
+
title = (col("title") || col("t\xEAn") || cols[2] || "").replace(/\*\*/g, "").trim();
|
|
10991
|
+
objective = col("learning objective") || col("objective") || col("m\u1EE5c ti\xEAu") || "";
|
|
10992
|
+
concept = col("key concept") || col("concept") || col("kh\xE1i ni\u1EC7m") || "";
|
|
10993
|
+
keywordsStr = col("keywords") || col("t\u1EEB kh\xF3a") || "";
|
|
10994
|
+
} else {
|
|
10995
|
+
lessonCode = (cols[1] || "").replace(/\*\*/g, "").trim();
|
|
10996
|
+
title = (cols[2] || "").replace(/\*\*/g, "").trim();
|
|
10997
|
+
objective = cols[5] || "";
|
|
10998
|
+
concept = cols[4] || "";
|
|
10999
|
+
}
|
|
11000
|
+
if (lessonCode && /^[A-Za-z0-9_\-]+$/.test(lessonCode)) {
|
|
11001
|
+
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) : [];
|
|
11002
|
+
sessions.push({
|
|
11003
|
+
id: lessonCode,
|
|
11004
|
+
order: sessions.length + 1,
|
|
11005
|
+
title: title || lessonCode,
|
|
11006
|
+
prose_objective: objective,
|
|
11007
|
+
new_keywords: keywords
|
|
11008
|
+
});
|
|
11009
|
+
}
|
|
11010
|
+
}
|
|
11011
|
+
if (sessions.length > 0) {
|
|
11012
|
+
return sessions;
|
|
11013
|
+
}
|
|
11014
|
+
}
|
|
11015
|
+
return [];
|
|
11016
|
+
}
|
|
11017
|
+
async function extractCurriculumHorizon(opts) {
|
|
11018
|
+
const { plan, frameworkMarkdown, targetLessonId, storage, projectId } = opts;
|
|
11019
|
+
const sessions = parseAllSessions(plan, frameworkMarkdown);
|
|
11020
|
+
if (sessions.length === 0) {
|
|
11021
|
+
throw new CurriculumError({
|
|
11022
|
+
errorCode: "ERR_LESSON_NOT_IN_SOT",
|
|
11023
|
+
lessonId: targetLessonId,
|
|
11024
|
+
message: `[CurriculumHorizon] No sessions could be parsed from CURRICULUM_PLAN.json or CURRICULUM_FRAMEWORK.md. Fail fast \u2014 cannot construct curriculum horizon without SOT.`,
|
|
11025
|
+
suggestedAction: "Ensure CURRICULUM_PLAN.json or CURRICULUM_FRAMEWORK.md is generated and contains valid sessions.",
|
|
11026
|
+
retryable: false
|
|
11027
|
+
});
|
|
11028
|
+
}
|
|
11029
|
+
const targetCodePattern = new RegExp("^" + targetLessonId.replace(/_/g, "[_-]") + "$", "i");
|
|
11030
|
+
const targetIndex = sessions.findIndex(
|
|
11031
|
+
(s) => s.id === targetLessonId || targetCodePattern.test(s.id)
|
|
11032
|
+
);
|
|
11033
|
+
if (targetIndex < 0) {
|
|
11034
|
+
throw new CurriculumError({
|
|
11035
|
+
errorCode: "ERR_LESSON_NOT_IN_SOT",
|
|
11036
|
+
lessonId: targetLessonId,
|
|
11037
|
+
message: `[CurriculumHorizon] Lesson "${targetLessonId}" was not found among the ${sessions.length} planned sessions. Fail fast \u2014 refusing to generate unanchored lesson.`,
|
|
11038
|
+
suggestedAction: `Check lesson id against planned sessions: [${sessions.map((s) => s.id).join(", ")}]`,
|
|
11039
|
+
retryable: false
|
|
11040
|
+
});
|
|
11041
|
+
}
|
|
11042
|
+
const currentSession = sessions[targetIndex];
|
|
11043
|
+
const compactEnd = Math.max(0, targetIndex - DETAILED_BRIDGE_WINDOW);
|
|
11044
|
+
const compactSessions = sessions.slice(0, compactEnd);
|
|
11045
|
+
const masteredKeywords = Array.from(
|
|
11046
|
+
new Set(
|
|
11047
|
+
compactSessions.flatMap((s) => s.new_keywords || []).map((k) => k.trim()).filter(Boolean)
|
|
11048
|
+
)
|
|
11049
|
+
);
|
|
11050
|
+
const masteredConcepts = Array.from(
|
|
11051
|
+
new Set(
|
|
11052
|
+
compactSessions.map((s) => s.title || s.prose_objective || "").map((t) => t.trim()).filter(Boolean)
|
|
11053
|
+
)
|
|
11054
|
+
);
|
|
11055
|
+
const bridgeStart = Math.max(0, targetIndex - DETAILED_BRIDGE_WINDOW);
|
|
11056
|
+
const bridgeSessions = sessions.slice(bridgeStart, targetIndex);
|
|
11057
|
+
const detailedBridge = [];
|
|
11058
|
+
for (const session of bridgeSessions) {
|
|
11059
|
+
const bridgeIndex = sessions.indexOf(session) + 1;
|
|
11060
|
+
const bridge = {
|
|
11061
|
+
lessonId: session.id,
|
|
11062
|
+
lessonIndex: bridgeIndex,
|
|
11063
|
+
title: session.title,
|
|
11064
|
+
proseObjective: session.prose_objective,
|
|
11065
|
+
keywords: session.new_keywords || []
|
|
11066
|
+
};
|
|
11067
|
+
if (storage && projectId) {
|
|
11068
|
+
try {
|
|
11069
|
+
const candidates = [
|
|
11070
|
+
`_content/${session.id.replace(/_L\d+$/, "")}/LESSON_${session.id}.md`,
|
|
11071
|
+
`_content/LESSON_${session.id}.md`,
|
|
11072
|
+
`LESSON_${session.id}.md`
|
|
11073
|
+
];
|
|
11074
|
+
let lessonMd = "";
|
|
11075
|
+
for (const c of candidates) {
|
|
11076
|
+
try {
|
|
11077
|
+
const raw = await storage.readArtifact(projectId, c);
|
|
11078
|
+
if (raw) {
|
|
11079
|
+
lessonMd = raw;
|
|
11080
|
+
break;
|
|
11081
|
+
}
|
|
11082
|
+
} catch {
|
|
11083
|
+
}
|
|
11084
|
+
}
|
|
11085
|
+
if (lessonMd) {
|
|
11086
|
+
const ledger = extractSymbolLedger(lessonMd);
|
|
11087
|
+
if (ledger.primarySymbol || ledger.entryFileName || ledger.keySymbols.length > 0) {
|
|
11088
|
+
bridge.symbolLedger = {
|
|
11089
|
+
primaryStructOrClass: ledger.primarySymbol,
|
|
11090
|
+
mainEntryFile: ledger.entryFileName,
|
|
11091
|
+
keyVariables: ledger.keySymbols
|
|
11092
|
+
};
|
|
11093
|
+
}
|
|
11094
|
+
}
|
|
11095
|
+
} catch {
|
|
11096
|
+
}
|
|
11097
|
+
}
|
|
11098
|
+
detailedBridge.push(bridge);
|
|
11099
|
+
}
|
|
11100
|
+
const peekStart = targetIndex + 1;
|
|
11101
|
+
const peekEnd = Math.min(sessions.length, peekStart + BOUNDARY_PEEK_WINDOW);
|
|
11102
|
+
const boundaryPeek = sessions.slice(peekStart, peekEnd).map((s, idx) => ({
|
|
11103
|
+
lessonId: s.id,
|
|
11104
|
+
lessonIndex: peekStart + idx + 1,
|
|
11105
|
+
title: s.title,
|
|
11106
|
+
keywords: s.new_keywords || []
|
|
11107
|
+
}));
|
|
11108
|
+
return {
|
|
11109
|
+
targetLessonId,
|
|
11110
|
+
targetLessonIndex: targetIndex + 1,
|
|
11111
|
+
totalLessons: sessions.length,
|
|
11112
|
+
targetTitle: currentSession.title,
|
|
11113
|
+
targetKeywords: currentSession.new_keywords || [],
|
|
11114
|
+
compactMasterySet: {
|
|
11115
|
+
masteredKeywords,
|
|
11116
|
+
masteredConcepts
|
|
11117
|
+
},
|
|
11118
|
+
detailedBridge,
|
|
11119
|
+
boundaryPeek
|
|
11120
|
+
};
|
|
11121
|
+
}
|
|
11122
|
+
function renderHorizonPromptBlock(horizon) {
|
|
11123
|
+
const {
|
|
11124
|
+
targetLessonId,
|
|
11125
|
+
targetLessonIndex,
|
|
11126
|
+
totalLessons,
|
|
11127
|
+
targetTitle,
|
|
11128
|
+
targetKeywords,
|
|
11129
|
+
compactMasterySet,
|
|
11130
|
+
detailedBridge,
|
|
11131
|
+
boundaryPeek
|
|
11132
|
+
} = horizon;
|
|
11133
|
+
const lines = [
|
|
11134
|
+
`# \u{1F9ED} CURRICULUM HORIZON & SCAFFOLDING MATRIX (Lesson ${targetLessonIndex}/${totalLessons}: "${targetTitle}" [${targetLessonId}])`
|
|
11135
|
+
];
|
|
11136
|
+
if (compactMasterySet.masteredKeywords.length > 0 || compactMasterySet.masteredConcepts.length > 0) {
|
|
11137
|
+
const rawKeywords = compactMasterySet.masteredKeywords;
|
|
11138
|
+
const displayedKeywords = rawKeywords.length > 20 ? rawKeywords.slice(-20) : rawKeywords;
|
|
11139
|
+
const vocab = displayedKeywords.map((k) => `\`${k}\``).join(", ");
|
|
11140
|
+
const moreSuffix = rawKeywords.length > 20 ? ` *(+${rawKeywords.length - 20} earlier terms)*` : "";
|
|
11141
|
+
const concepts = compactMasterySet.masteredConcepts.length > 0 ? `
|
|
11142
|
+
- **Prior Concept Foundations:** ${compactMasterySet.masteredConcepts.slice(-3).join("; ")}` : "";
|
|
11143
|
+
lines.push(
|
|
11144
|
+
`
|
|
11145
|
+
## 1. \u{1F393} MASTERED VOCABULARY (Prior Lessons 1..${Math.max(1, targetLessonIndex - 3)} \u2014 Compact Set):`,
|
|
11146
|
+
`- **Mastered Terms & Syntax:** ${vocab || "(Core fundamentals)"}${moreSuffix}${concepts}`
|
|
11147
|
+
);
|
|
11148
|
+
} else if (targetLessonIndex === 1) {
|
|
11149
|
+
lines.push(
|
|
11150
|
+
`
|
|
11151
|
+
## 1. \u{1F393} PRIOR KNOWLEDGE FRONTIER:`,
|
|
11152
|
+
`- **Entry Point:** Inaugural lesson (Lesson 1/${totalLessons}). Students have no prior course vocabulary. All concepts must be introduced from baseline.`
|
|
11153
|
+
);
|
|
11154
|
+
}
|
|
11155
|
+
if (detailedBridge.length > 0) {
|
|
11156
|
+
lines.push(`
|
|
11157
|
+
## 2. \u{1F309} IMMEDIATE PREDECESSOR CONTEXT (Bridge Lessons):`);
|
|
11158
|
+
for (const bridge of detailedBridge) {
|
|
11159
|
+
lines.push(`### Lesson ${bridge.lessonIndex} (${bridge.lessonId}): ${bridge.title}`);
|
|
11160
|
+
if (bridge.proseObjective) {
|
|
11161
|
+
const obj = bridge.proseObjective.length > 120 ? bridge.proseObjective.slice(0, 117) + "..." : bridge.proseObjective;
|
|
11162
|
+
lines.push(`- **Objective:** ${obj}`);
|
|
11163
|
+
}
|
|
11164
|
+
if (bridge.keywords.length > 0) {
|
|
11165
|
+
lines.push(`- **Keywords:** ${bridge.keywords.map((k) => `\`${k}\``).join(", ")}`);
|
|
11166
|
+
}
|
|
11167
|
+
if (bridge.symbolLedger) {
|
|
11168
|
+
const parts = [];
|
|
11169
|
+
if (bridge.symbolLedger.primaryStructOrClass) {
|
|
11170
|
+
parts.push(`Primary Struct: \`${bridge.symbolLedger.primaryStructOrClass}\``);
|
|
11171
|
+
}
|
|
11172
|
+
if (bridge.symbolLedger.mainEntryFile) {
|
|
11173
|
+
parts.push(`Entry File: \`${bridge.symbolLedger.mainEntryFile}\``);
|
|
11174
|
+
}
|
|
11175
|
+
if (bridge.symbolLedger.keyVariables?.length) {
|
|
11176
|
+
parts.push(`Symbols: ${bridge.symbolLedger.keyVariables.map((v) => `\`${v}\``).join(", ")}`);
|
|
11177
|
+
}
|
|
11178
|
+
if (parts.length > 0) {
|
|
11179
|
+
lines.push(`- **Code Symbol Ledger:** ${parts.join(" | ")}`);
|
|
11180
|
+
}
|
|
11181
|
+
}
|
|
11182
|
+
}
|
|
11183
|
+
lines.push(
|
|
11184
|
+
`\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}.`
|
|
11185
|
+
);
|
|
11186
|
+
}
|
|
11187
|
+
const currentKeywordsStr = targetKeywords.length > 0 ? targetKeywords.map((k) => `\`${k}\``).join(", ") : "`Current Lesson Concepts`";
|
|
11188
|
+
lines.push(
|
|
11189
|
+
`
|
|
11190
|
+
## 3. \u{1F3AF} ALLOWED DESIGN SPACE (Positive-Only Allow List):`,
|
|
11191
|
+
`- **Student Toolkit:** Mastered Vocabulary + Immediate Bridge Keywords + Current Lesson Scope (${currentKeywordsStr}).`,
|
|
11192
|
+
`- **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!`
|
|
11193
|
+
);
|
|
11194
|
+
if (boundaryPeek.length > 0) {
|
|
11195
|
+
const nextLesson = boundaryPeek[0];
|
|
11196
|
+
const nextKeywords = nextLesson.keywords.length > 0 ? nextLesson.keywords.map((k) => `\`${k}\``).join(", ") : "upcoming features";
|
|
11197
|
+
lines.push(
|
|
11198
|
+
`
|
|
11199
|
+
## 4. \u{1F6A7} BOUNDARY (Next Lesson Peek):`,
|
|
11200
|
+
`- **Upcoming Lesson ${nextLesson.lessonIndex} ("${nextLesson.title}"):** Introduces ${nextKeywords}.`,
|
|
11201
|
+
`- **BOUNDARY MANDATE:** These concepts are NOT yet available to the student. Do not introduce or require these future concepts.`
|
|
11202
|
+
);
|
|
11203
|
+
}
|
|
11204
|
+
return lines.join("\n");
|
|
11205
|
+
}
|
|
11206
|
+
function validateHorizonCompliance(artifactContent, horizon) {
|
|
11207
|
+
const issues = [];
|
|
11208
|
+
const forbiddenMatches = [];
|
|
11209
|
+
if (!artifactContent || horizon.boundaryPeek.length === 0) {
|
|
11210
|
+
return { compliant: true, issues: [], forbiddenMatches: [] };
|
|
11211
|
+
}
|
|
11212
|
+
const contentLower = artifactContent.toLowerCase();
|
|
11213
|
+
const immediateNext = horizon.boundaryPeek[0];
|
|
11214
|
+
if (immediateNext && immediateNext.keywords.length > 0) {
|
|
11215
|
+
for (const kw of immediateNext.keywords) {
|
|
11216
|
+
const trimmed = kw.trim().toLowerCase();
|
|
11217
|
+
if (trimmed.length <= 2) continue;
|
|
11218
|
+
const pattern = new RegExp(`\\b${trimmed.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "i");
|
|
11219
|
+
if (pattern.test(contentLower)) {
|
|
11220
|
+
const inMastered = horizon.compactMasterySet.masteredKeywords.some(
|
|
11221
|
+
(m) => m.toLowerCase() === trimmed
|
|
11222
|
+
);
|
|
11223
|
+
const inBridge = horizon.detailedBridge.some(
|
|
11224
|
+
(b) => b.keywords.some((bk) => bk.toLowerCase() === trimmed)
|
|
11225
|
+
);
|
|
11226
|
+
const inCurrent = horizon.targetKeywords.some(
|
|
11227
|
+
(ck) => ck.toLowerCase() === trimmed
|
|
11228
|
+
);
|
|
11229
|
+
if (!inMastered && !inBridge && !inCurrent) {
|
|
11230
|
+
forbiddenMatches.push(kw);
|
|
11231
|
+
issues.push(
|
|
11232
|
+
`Artifact contains boundary concept "${kw}" scheduled for future Lesson ${immediateNext.lessonIndex} ("${immediateNext.title}").`
|
|
11233
|
+
);
|
|
11234
|
+
}
|
|
11235
|
+
}
|
|
11236
|
+
}
|
|
11237
|
+
}
|
|
11238
|
+
return {
|
|
11239
|
+
compliant: issues.length === 0,
|
|
11240
|
+
issues,
|
|
11241
|
+
forbiddenMatches
|
|
11242
|
+
};
|
|
11243
|
+
}
|
|
11244
|
+
|
|
10679
11245
|
// src/services/contextBuilder.ts
|
|
10680
11246
|
var DEFAULT_LESSON_PRIORITIES = [
|
|
11247
|
+
"Symbol & Identifier Ledger",
|
|
11248
|
+
"Artifact Contract",
|
|
10681
11249
|
"A. Lesson Design Plan",
|
|
10682
11250
|
"B. Lesson Flow",
|
|
10683
11251
|
"Learning Objectives & Evidence",
|
|
@@ -10896,6 +11464,12 @@ function normalizeHeading(str) {
|
|
|
10896
11464
|
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
10897
11465
|
}
|
|
10898
11466
|
function findCanonicalFuzzy(norm) {
|
|
11467
|
+
if (norm.includes("symbol") || norm.includes("identifier ledger") || norm.includes("dinh danh")) {
|
|
11468
|
+
return "Symbol & Identifier Ledger";
|
|
11469
|
+
}
|
|
11470
|
+
if (norm.includes("artifact contract") || norm.includes("hop dong hoc lieu")) {
|
|
11471
|
+
return "Artifact Contract";
|
|
11472
|
+
}
|
|
10899
11473
|
if (norm.includes("lesson design plan") || norm.includes("ke hoach thiet ke")) {
|
|
10900
11474
|
return "A. Lesson Design Plan";
|
|
10901
11475
|
}
|
|
@@ -10946,6 +11520,39 @@ function deriveArtifactTypeFromFileName(fileName) {
|
|
|
10946
11520
|
const token = base.match(/^([A-Z][A-Z0-9_]*?)(?=_|$)/);
|
|
10947
11521
|
return token ? token[1] : void 0;
|
|
10948
11522
|
}
|
|
11523
|
+
function extractSymbolLedger(lessonMarkdown) {
|
|
11524
|
+
const result = {
|
|
11525
|
+
keySymbols: [],
|
|
11526
|
+
rawBlock: ""
|
|
11527
|
+
};
|
|
11528
|
+
if (!lessonMarkdown) return result;
|
|
11529
|
+
const ledgerMatch = lessonMarkdown.match(/###?\s*(?:Symbol & Identifier Ledger|Bảng Định Danh|Artifact Contract)[\s\S]*?(?=\n##|\n---|$)/i);
|
|
11530
|
+
if (ledgerMatch) {
|
|
11531
|
+
result.rawBlock = ledgerMatch[0].trim();
|
|
11532
|
+
}
|
|
11533
|
+
const structMatch = lessonMarkdown.match(/(?:Primary Struct|Primary Class|Primary Function|Main Component|Primary Module|Struct chính|Class chính|Hàm chính)[:\s*`]+([A-Za-z0-9_]+)/i);
|
|
11534
|
+
if (structMatch) {
|
|
11535
|
+
result.primarySymbol = structMatch[1];
|
|
11536
|
+
result.keySymbols.push(structMatch[1]);
|
|
11537
|
+
} else {
|
|
11538
|
+
const codeStructMatch = lessonMarkdown.match(/(?:struct|class|interface|type|def|function)\s+([A-Za-z0-9_]+)/);
|
|
11539
|
+
if (codeStructMatch) {
|
|
11540
|
+
const sym = codeStructMatch[1];
|
|
11541
|
+
result.primarySymbol = sym;
|
|
11542
|
+
result.keySymbols.push(sym);
|
|
11543
|
+
}
|
|
11544
|
+
}
|
|
11545
|
+
const fileMatch = lessonMarkdown.match(/(?:Entry File|Source File|Target File|Tên file mã nguồn)[:\s*`]+([A-Za-z0-9_\-\.]+\.[a-z0-9_]+)/i);
|
|
11546
|
+
if (fileMatch) {
|
|
11547
|
+
result.entryFileName = fileMatch[1];
|
|
11548
|
+
} else {
|
|
11549
|
+
const codeFileComment = lessonMarkdown.match(/(?:\/\/\s*|#\s*|\/\*\s*)([A-Za-z0-9_\-]+\.[a-zA-Z0-9]+)/);
|
|
11550
|
+
if (codeFileComment) {
|
|
11551
|
+
result.entryFileName = codeFileComment[1];
|
|
11552
|
+
}
|
|
11553
|
+
}
|
|
11554
|
+
return result;
|
|
11555
|
+
}
|
|
10949
11556
|
|
|
10950
11557
|
// src/services/knowledgeExpositionService.ts
|
|
10951
11558
|
var EXPOSITION_REL = (lessonCode) => "_sot/expositions/" + lessonCode + ".md";
|
|
@@ -10965,8 +11572,22 @@ var DEPTH_RULES = {
|
|
|
10965
11572
|
cio: "Write WHAT + WHY + HOW: include the mechanism, step by step, still technology-independent.",
|
|
10966
11573
|
sio: "Write WHAT + WHY + HOW + SPECIFIC: include concrete implementations and how the real project keywords are used."
|
|
10967
11574
|
};
|
|
10968
|
-
function
|
|
11575
|
+
function buildDomainLexiconGuardrail(techStack, hardwarePlatform) {
|
|
11576
|
+
const targetTech = (techStack || "").trim();
|
|
11577
|
+
const targetHw = (hardwarePlatform || "").trim();
|
|
11578
|
+
const platformAnchor = [targetTech, targetHw].filter(Boolean).join(" | ");
|
|
11579
|
+
if (!platformAnchor) {
|
|
11580
|
+
return `- \u{1F512} TECHNICAL DOMAIN ANCHOR: Strictly adhere to the declared curriculum domain. Use ONLY native, standard, idiomatic syntax and mechanisms. Strictly FORBIDDEN from using foreign paradigms, cross-domain jargon, or hallucinated APIs.`;
|
|
11581
|
+
}
|
|
11582
|
+
return `- \u{1F512} STRICT DOMAIN & TECHNICAL PLATFORM ANCHOR:
|
|
11583
|
+
\u2022 Declared Platform: "${platformAnchor}"
|
|
11584
|
+
\u2022 NATIVE PARADIGM ONLY: You MUST strictly use standard, idiomatic syntax, conventions, naming patterns, and mental models of "${platformAnchor}".
|
|
11585
|
+
\u2022 ANTI-CONTAMINATION INVARIANT: Strictly FORBIDDEN from importing or using syntax, units, keywords, tags, or concepts from unrelated/foreign ecosystems (e.g., do NOT leak Web/HTML/CSS tags or units into native mobile/embedded stacks, do NOT leak dynamic scripting into statically typed systems, do NOT use hardware/circuit terminology in pure-software courses).
|
|
11586
|
+
\u2022 REAL APIS ONLY: Every method, modifier, property, and API referenced must exist in the standard SDK of "${platformAnchor}".`;
|
|
11587
|
+
}
|
|
11588
|
+
function buildSystemPrompt(targetLanguage = "vi", techStack, hardwarePlatform) {
|
|
10969
11589
|
const langDirective = buildLanguageDirective(targetLanguage);
|
|
11590
|
+
const domainGuardrails = buildDomainLexiconGuardrail(techStack, hardwarePlatform);
|
|
10970
11591
|
return [
|
|
10971
11592
|
"You write KNOWLEDGE_EXPOSITION: self-study reading material for a student in a teacherless program.",
|
|
10972
11593
|
"Rules:",
|
|
@@ -10975,6 +11596,7 @@ function buildSystemPrompt(targetLanguage = "vi") {
|
|
|
10975
11596
|
"3. Respect each concept depth target (ULO/CIO/SIO) \u2014 do not overshoot.",
|
|
10976
11597
|
"4. Student-facing only: no teacher instructions, no classroom management text.",
|
|
10977
11598
|
"5. Output the full markdown document following the provided section skeleton exactly (headers and placeholders preserved).",
|
|
11599
|
+
domainGuardrails,
|
|
10978
11600
|
langDirective
|
|
10979
11601
|
].join("\n");
|
|
10980
11602
|
}
|
|
@@ -11011,7 +11633,7 @@ function buildUserPrompt(session, plan, glossary, targetLanguage = "vi", slcMark
|
|
|
11011
11633
|
].filter(Boolean).join("\n");
|
|
11012
11634
|
}
|
|
11013
11635
|
async function ensureKnowledgeExposition(options) {
|
|
11014
|
-
const { projectId, lessonCode, plan, glossary, llmFn, storage } = options;
|
|
11636
|
+
const { projectId, lessonCode, plan, glossary, llmFn, storage, techStack, hardwarePlatform } = options;
|
|
11015
11637
|
const session = plan.sessions.find((s) => s.id === lessonCode);
|
|
11016
11638
|
if (!session) throw new Error("Session " + lessonCode + " not found in plan " + plan.plan_id);
|
|
11017
11639
|
const existing = await storage.readArtifact(projectId, EXPOSITION_REL(lessonCode));
|
|
@@ -11026,7 +11648,7 @@ async function ensureKnowledgeExposition(options) {
|
|
|
11026
11648
|
}
|
|
11027
11649
|
const targetLanguage = options.targetLanguage || plan.translation?.target_language || "vi";
|
|
11028
11650
|
const content = (await llmFn(
|
|
11029
|
-
buildSystemPrompt(targetLanguage),
|
|
11651
|
+
buildSystemPrompt(targetLanguage, techStack, hardwarePlatform),
|
|
11030
11652
|
buildUserPrompt(session, plan, glossary, targetLanguage, options.slcMarkdown)
|
|
11031
11653
|
)).trim();
|
|
11032
11654
|
if (content.length < 200) {
|
|
@@ -11096,6 +11718,18 @@ async function ensureExpositionForLesson(storage, projectId, lessonCode, options
|
|
|
11096
11718
|
}
|
|
11097
11719
|
const scopedTerms = new Set(plan.glossary_scope.find((g) => g.session_id === lessonCode)?.terms ?? []);
|
|
11098
11720
|
glossary = glossary.filter((g) => scopedTerms.has(g.term));
|
|
11721
|
+
let hw = options.hardwarePlatform;
|
|
11722
|
+
let tech = options.techStack;
|
|
11723
|
+
if (!hw || !tech) {
|
|
11724
|
+
try {
|
|
11725
|
+
const lpRaw = await storage.readSotDocument(projectId, "LEARNER_PROFILE.md");
|
|
11726
|
+
if (lpRaw) {
|
|
11727
|
+
const hwMatch = lpRaw.match(/(?:Student Equipment|Hardware|Platform|Thiết bị)[:\s*`]+([^\n\r]+)/i);
|
|
11728
|
+
if (hwMatch && !hw) hw = hwMatch[1].trim();
|
|
11729
|
+
}
|
|
11730
|
+
} catch {
|
|
11731
|
+
}
|
|
11732
|
+
}
|
|
11099
11733
|
const { runCurriculumAIInference: runCurriculumAIInference2 } = await Promise.resolve().then(() => (init_streamRunner(), streamRunner_exports));
|
|
11100
11734
|
const targetLang = options.targetLanguage || plan.translation?.target_language || "vi";
|
|
11101
11735
|
const result = await ensureKnowledgeExposition({
|
|
@@ -11105,6 +11739,8 @@ async function ensureExpositionForLesson(storage, projectId, lessonCode, options
|
|
|
11105
11739
|
glossary,
|
|
11106
11740
|
targetLanguage: targetLang,
|
|
11107
11741
|
slcMarkdown: options.slcMarkdown,
|
|
11742
|
+
techStack: tech,
|
|
11743
|
+
hardwarePlatform: hw,
|
|
11108
11744
|
llmFn: async (systemPrompt, userPrompt) => {
|
|
11109
11745
|
const runnerOpts = options.customInference ? { customInference: options.customInference } : {};
|
|
11110
11746
|
const out = await runCurriculumAIInference2(
|
|
@@ -25131,7 +25767,11 @@ type: "LESSON_EDP"
|
|
|
25131
25767
|
|
|
25132
25768
|
### 3. Resource Map (Slide, Handout, Starter Code, Lab Tools)
|
|
25133
25769
|
### 4. Assessment Map (Rubric criteria, formative checkpoints, remediation paths)
|
|
25134
|
-
### 5. Artifact Contract
|
|
25770
|
+
### 5. Artifact Contract & Code Symbol Ledger
|
|
25771
|
+
- **Primary Struct / Class / Component:** [Explicit canonical identifier e.g. ProfileCardView]
|
|
25772
|
+
- **Entry Source File:** [Explicit file name e.g. ProfileCardView.swift]
|
|
25773
|
+
- **Key Functions & State Variables:** [Canonical identifiers used across all student activities]
|
|
25774
|
+
- **Artifact Specifications:** [Deliverable requirements for ACT, SLIDE, QUIZ, GUIDE, WKS, CODE, EXT]
|
|
25135
25775
|
|
|
25136
25776
|
---
|
|
25137
25777
|
|
|
@@ -25181,7 +25821,11 @@ type: "LESSON_GENERAL"
|
|
|
25181
25821
|
|
|
25182
25822
|
### 3. Resource Map
|
|
25183
25823
|
### 4. Assessment Map
|
|
25184
|
-
### 5. Artifact Contract
|
|
25824
|
+
### 5. Artifact Contract & Code Symbol Ledger
|
|
25825
|
+
- **Primary Struct / Class / Component:** [Explicit canonical identifier e.g. MainComponent]
|
|
25826
|
+
- **Entry Source File:** [Explicit file name e.g. MainComponent.ext]
|
|
25827
|
+
- **Key Functions & State Variables:** [Canonical identifiers used across all student activities]
|
|
25828
|
+
- **Artifact Specifications:** [Deliverable requirements for ACT, SLIDE, QUIZ, GUIDE, WKS, CODE, EXT]
|
|
25185
25829
|
|
|
25186
25830
|
---
|
|
25187
25831
|
|
|
@@ -25229,7 +25873,11 @@ type: "LESSON_5E"
|
|
|
25229
25873
|
|
|
25230
25874
|
### 3. Resource Map
|
|
25231
25875
|
### 4. Assessment Map
|
|
25232
|
-
### 5. Artifact Contract
|
|
25876
|
+
### 5. Artifact Contract & Code Symbol Ledger
|
|
25877
|
+
- **Primary Struct / Class / Component:** [Explicit canonical identifier e.g. MainComponent]
|
|
25878
|
+
- **Entry Source File:** [Explicit file name e.g. MainComponent.ext]
|
|
25879
|
+
- **Key Functions & State Variables:** [Canonical identifiers used across all student activities]
|
|
25880
|
+
- **Artifact Specifications:** [Deliverable requirements for ACT, SLIDE, QUIZ, GUIDE, WKS, CODE, EXT]
|
|
25233
25881
|
|
|
25234
25882
|
---
|
|
25235
25883
|
|
|
@@ -25408,6 +26056,32 @@ async function produceSingleLesson(storage, projectId, lessonId, options = {}) {
|
|
|
25408
26056
|
|
|
25409
26057
|
[CURRICULUM FRAMEWORK EXCERPT]:
|
|
25410
26058
|
${buildFrameworkExcerptForLesson(framework, lessonId)}`;
|
|
26059
|
+
let horizon = null;
|
|
26060
|
+
let horizonBlock = "";
|
|
26061
|
+
try {
|
|
26062
|
+
let planObj = null;
|
|
26063
|
+
const planRaw = await storage.readArtifact(projectId, "_sot/CURRICULUM_PLAN.json");
|
|
26064
|
+
if (planRaw) {
|
|
26065
|
+
try {
|
|
26066
|
+
planObj = JSON.parse(planRaw);
|
|
26067
|
+
} catch {
|
|
26068
|
+
}
|
|
26069
|
+
}
|
|
26070
|
+
horizon = await extractCurriculumHorizon({
|
|
26071
|
+
plan: planObj,
|
|
26072
|
+
frameworkMarkdown: framework,
|
|
26073
|
+
targetLessonId: lessonCode,
|
|
26074
|
+
storage,
|
|
26075
|
+
projectId
|
|
26076
|
+
});
|
|
26077
|
+
if (horizon) {
|
|
26078
|
+
horizonBlock = `
|
|
26079
|
+
|
|
26080
|
+
${renderHorizonPromptBlock(horizon)}`;
|
|
26081
|
+
}
|
|
26082
|
+
} catch (hErr) {
|
|
26083
|
+
console.warn(`[produceSingleLesson] Notice: Curriculum Horizon extraction:`, hErr?.message || hErr);
|
|
26084
|
+
}
|
|
25411
26085
|
const glossaryBlock = glossaryContext ? `
|
|
25412
26086
|
|
|
25413
26087
|
[GLOSSARY TERMS (use these exact definitions)]:
|
|
@@ -25428,7 +26102,7 @@ ${sessionSliceContext}` : "";
|
|
|
25428
26102
|
${sg}
|
|
25429
26103
|
|
|
25430
26104
|
[REFERENCE PACK GROUND TRUTH]:
|
|
25431
|
-
${ref}${standardsBlock}${glossaryBlock}${expositionBlock}${sessionSliceBlock}`;
|
|
26105
|
+
${ref}${standardsBlock}${glossaryBlock}${expositionBlock}${sessionSliceBlock}${horizonBlock}`;
|
|
25432
26106
|
let commonContext = assembleCommonContext(effectiveRefPack, effectiveStyleGuide);
|
|
25433
26107
|
const MAX_COMPOSITE_PROMPT_CHARS = 3e4;
|
|
25434
26108
|
const runnerOptions = options.customInference ? { customInference: options.customInference } : {};
|
|
@@ -25804,17 +26478,23 @@ ${currentContent}` }],
|
|
|
25804
26478
|
artifactType: "LESSON"
|
|
25805
26479
|
});
|
|
25806
26480
|
const lessonExcerpt = lessonExcerptResult.excerpt;
|
|
25807
|
-
|
|
25808
|
-
source: "LESSON",
|
|
26481
|
+
({
|
|
25809
26482
|
verified: lessonExcerptResult.verified,
|
|
25810
26483
|
sectionAware: lessonExcerptResult.sectionAware,
|
|
25811
26484
|
issues: lessonExcerptResult.issues
|
|
25812
|
-
};
|
|
25813
|
-
|
|
26485
|
+
});
|
|
26486
|
+
const symbolLedger = extractSymbolLedger(lessonContent);
|
|
26487
|
+
const symbolLedgerBlock = symbolLedger.primarySymbol ? `
|
|
26488
|
+
|
|
26489
|
+
[MANDATORY CODE SYMBOL REGISTRY (Inherited from LESSON Plan)]:
|
|
26490
|
+
- Primary Struct / Class / Component: \`${symbolLedger.primarySymbol}\`
|
|
26491
|
+
- Entry Source File: \`${symbolLedger.entryFileName || symbolLedger.primarySymbol}\`
|
|
26492
|
+
- Key Identifiers to inherit verbatim: ${symbolLedger.keySymbols.map((s) => `\`${s}\``).join(", ")}
|
|
26493
|
+
- INVARIANT: You MUST use these exact identifier names in all code examples, exercises, and test assertions. Do NOT invent new struct/class names!` : "";
|
|
25814
26494
|
const satelliteContext = `${commonContext}
|
|
25815
26495
|
|
|
25816
26496
|
[CANONICAL LESSON PLAN (${pedagogyLabel})]:
|
|
25817
|
-
${lessonExcerpt}`;
|
|
26497
|
+
${lessonExcerpt}${symbolLedgerBlock}`;
|
|
25818
26498
|
const judgeSat = (sat, content) => {
|
|
25819
26499
|
if (gateModeFor(gates, sat) !== "LLM_JUDGE") return Promise.resolve();
|
|
25820
26500
|
return judgeSatelliteArtifact({
|
|
@@ -26317,6 +26997,12 @@ ${buildHeadingDirective("CODE", slcMarkdown, targetLang)}`;
|
|
|
26317
26997
|
c3: "### Challenge 3: [Name] (Difficulty: \u2B50\u2B50\u2B50\u2B50\u2B50) \u2014 Extension Milestones (Level 1: Ninja \u2192 Level 2: Guru \u2192 Level 3: Master)",
|
|
26318
26998
|
meta: "## [REQUIRED] Metacognitive Deep Dive & Engineering Trade-offs"
|
|
26319
26999
|
};
|
|
27000
|
+
const zpdCeilingPrompt = horizon ? `
|
|
27001
|
+
4. \u{1F3AF} CURRICULUM HORIZON ALLOWED SPACE & BOUNDARY MANDATE:
|
|
27002
|
+
- Student's COMPLETE allowed toolkit = Mastered Vocabulary + Immediate Bridge + Current Lesson Scope (${horizon.targetKeywords.join(", ") || "Current Lesson Concepts"}).
|
|
27003
|
+
- All extension challenges MUST be 100% solvable using ONLY items within this toolkit.
|
|
27004
|
+
${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.` : ""}` : `
|
|
27005
|
+
4. ZPD SCOPE: Focus on architectural edge cases, algorithmic optimization, and creative variations within current and past lesson concepts.`;
|
|
26320
27006
|
const extPrompt = `You are @activity (Lead STEM Specialist & Differentiated Extension Designer).
|
|
26321
27007
|
Based on Master Lesson Plan \`LESSON_${lessonCode}.md\`, author the advanced extension challenge: \`EXT_${lessonCode}.md\`.
|
|
26322
27008
|
|
|
@@ -26348,6 +27034,7 @@ ${extHeadings.sub}
|
|
|
26348
27034
|
- ${extHeadings.c3}
|
|
26349
27035
|
- ${extHeadings.meta}
|
|
26350
27036
|
3. Output 100% clean Markdown directly \u2014 NO code fences around the document.
|
|
27037
|
+
${zpdCeilingPrompt}
|
|
26351
27038
|
|
|
26352
27039
|
${languageDirective}
|
|
26353
27040
|
|
|
@@ -26878,6 +27565,29 @@ async function generateSingleArtifact(req) {
|
|
|
26878
27565
|
const artifactSpecializedPrompt = getArtifactSpecializedInvariants(artifactType, {
|
|
26879
27566
|
...req,
|
|
26880
27567
|
studentCount});
|
|
27568
|
+
const techStack = req.config?.techStack || req.hardwarePlatform?.[0] || "Declared Technical Domain";
|
|
27569
|
+
const domainGuardrail = buildDomainLexiconGuardrail(techStack, hwStr);
|
|
27570
|
+
const symbolLedger = contextSot.lessonPlan ? extractSymbolLedger(contextSot.lessonPlan) : null;
|
|
27571
|
+
const symbolLedgerPrompt = symbolLedger?.primarySymbol ? `
|
|
27572
|
+
7. MANDATORY CODE SYMBOL REGISTRY (Inherited from Canonical LESSON):
|
|
27573
|
+
- Primary Struct / Class: \`${symbolLedger.primarySymbol}\`
|
|
27574
|
+
- Entry Source File: \`${symbolLedger.entryFileName || symbolLedger.primarySymbol + ".swift"}\`
|
|
27575
|
+
- Key Identifiers to inherit: ${symbolLedger.keySymbols.map((s) => `\`${s}\``).join(", ")}
|
|
27576
|
+
- INVARIANT: You MUST use these exact identifier names in all code examples, exercises, and starter templates. Do NOT invent conflicting struct or class names.` : "";
|
|
27577
|
+
let horizon = contextSot.horizon || null;
|
|
27578
|
+
if (!horizon && (contextSot.plan || contextSot.framework) && lessonId) {
|
|
27579
|
+
try {
|
|
27580
|
+
horizon = await extractCurriculumHorizon({
|
|
27581
|
+
plan: contextSot.plan,
|
|
27582
|
+
frameworkMarkdown: contextSot.framework,
|
|
27583
|
+
targetLessonId: lessonId
|
|
27584
|
+
});
|
|
27585
|
+
} catch {
|
|
27586
|
+
}
|
|
27587
|
+
}
|
|
27588
|
+
const horizonPrompt = horizon ? `
|
|
27589
|
+
|
|
27590
|
+
${renderHorizonPromptBlock(horizon)}` : "";
|
|
26881
27591
|
const systemPrompt = `You are ${meta.persona}, an expert Curriculum & Pedagogical Specialist in the Curriculum OS Multi-Agent Team.
|
|
26882
27592
|
Your task is to author a canonical, publication-grade learning artifact of type "${artifactType.toUpperCase()}".
|
|
26883
27593
|
|
|
@@ -26888,7 +27598,10 @@ ${headingDirective}
|
|
|
26888
27598
|
3. PEDAGOGICAL GROUNDING: Strictly align with the ${pedagogy.toUpperCase()} model, Bloom's Revised Taxonomy, and IEEE/ACM CS2023 guidelines.
|
|
26889
27599
|
4. SCAFFOLDING LEVEL: "${scaffoldingLevel.toUpperCase()}".${scaffoldingRule}
|
|
26890
27600
|
5. TARGET AUDIENCE: ${gradeLevel ? `Grade ${gradeLevel}, ` : ""}${targetAge} on ${hwStr}.${deviceRule}${classDynamicsRule}${extraContextRule}
|
|
26891
|
-
6.
|
|
27601
|
+
6. DOMAIN & TECH STACK GUARDRAILS:
|
|
27602
|
+
${domainGuardrail}
|
|
27603
|
+
${symbolLedgerPrompt}
|
|
27604
|
+
8. OUTPUT INTEGRITY: Output clean Markdown starting directly with YAML frontmatter. Do not wrap entire response in triple backticks.${artifactSpecializedPrompt}${horizonPrompt}${mediaPolicy ? `
|
|
26892
27605
|
|
|
26893
27606
|
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).
|
|
26894
27607
|
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.` : ""}`;
|
|
@@ -27368,6 +28081,20 @@ ${includeUnitTests ? "- Unit Testing: Provide automated assertions or test runne
|
|
|
27368
28081
|
1. **CLASS-SCALED INVENTORY FOR ${studentCount} STUDENTS**:
|
|
27369
28082
|
- Exact quantities calculated for ${studentCount} students.
|
|
27370
28083
|
- Component specifications, estimated unit cost, and affordable alternatives.`;
|
|
28084
|
+
case "ext": {
|
|
28085
|
+
const zpdCeilingRule = `- \u{1F3AF} CURRICULUM HORIZON ALLOWED SPACE & BOUNDARY MANDATE:
|
|
28086
|
+
\u2022 SCOPE LOCK: All extension challenges MUST be 100% solvable using ONLY items from the student's Mastered Vocabulary and Current Lesson Scope.
|
|
28087
|
+
\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).`;
|
|
28088
|
+
return `
|
|
28089
|
+
### \u{1F680} EXTENSION CHALLENGE ARCHITECTURE INVARIANTS:
|
|
28090
|
+
${zpdCeilingRule}
|
|
28091
|
+
1. **STRUCTURED 3-TIER CHALLENGES**:
|
|
28092
|
+
- Challenge 1 (Mission Briefing): High-stakes real-world scenario applying today's concepts.
|
|
28093
|
+
- Challenge 2 (Architectural Constraints & Edge Cases): Deeper technical rules without violating prerequisite boundaries.
|
|
28094
|
+
- Challenge 3 (Extension Milestones): Progressive milestones (Level 1: Novice \u2192 Level 2: Advanced \u2192 Level 3: Master).
|
|
28095
|
+
2. **METACOGNITIVE & ENGINEERING TRADE-OFFS**:
|
|
28096
|
+
- Explicit reflection prompts evaluating architectural choices, code maintainability, and design patterns.`;
|
|
28097
|
+
}
|
|
27371
28098
|
case "lesson": {
|
|
27372
28099
|
const lessonDuration = cfg.lessonDuration || 90;
|
|
27373
28100
|
const pedagogicalModel = cfg.pedagogicalModel || req.pedagogy || "5e";
|
|
@@ -30988,6 +31715,6 @@ function renderMediaPlaceholder(entry) {
|
|
|
30988
31715
|
return `> \u{1F5BC}\uFE0F [\u1EA2nh \u0111ang ch\u1EDD: ${entry.name} \u2014 s\u1EBD \u0111\u01B0\u1EE3c t\u1EA1o sau khi duy\u1EC7t media]`;
|
|
30989
31716
|
}
|
|
30990
31717
|
|
|
30991
|
-
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, 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, 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 };
|
|
31718
|
+
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, 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, 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 };
|
|
30992
31719
|
//# sourceMappingURL=index.mjs.map
|
|
30993
31720
|
//# sourceMappingURL=index.mjs.map
|