@thanh01.pmt/curriculum-kit 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/index.cjs +49 -0
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.d.cts +11 -1
- package/dist/ai/index.d.ts +11 -1
- package/dist/ai/index.mjs +49 -1
- package/dist/ai/index.mjs.map +1 -1
- package/dist/{gateSettings-Buk_MSML.d.cts → gateSettings-L3FR2-MO.d.cts} +1 -0
- package/dist/{gateSettings-Buk_MSML.d.ts → gateSettings-L3FR2-MO.d.ts} +1 -0
- package/dist/index.cjs +227 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.mjs +227 -32
- package/dist/index.mjs.map +1 -1
- package/dist/pipeline/index.cjs.map +1 -1
- package/dist/pipeline/index.mjs.map +1 -1
- package/dist/workflow/index.cjs +18 -0
- 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 +18 -0
- package/dist/workflow/index.mjs.map +1 -1
- package/package.json +2 -1
|
@@ -13,6 +13,7 @@ interface SingleArtifactRequest {
|
|
|
13
13
|
studentCount?: string;
|
|
14
14
|
language?: string;
|
|
15
15
|
sectionLanguageContract?: Record<string, Record<string, string>> | string;
|
|
16
|
+
slidesEngine?: 'html' | 'marp';
|
|
16
17
|
failClosedContext?: boolean;
|
|
17
18
|
extraContext?: string;
|
|
18
19
|
config?: Record<string, any>;
|
|
@@ -13,6 +13,7 @@ interface SingleArtifactRequest {
|
|
|
13
13
|
studentCount?: string;
|
|
14
14
|
language?: string;
|
|
15
15
|
sectionLanguageContract?: Record<string, Record<string, string>> | string;
|
|
16
|
+
slidesEngine?: 'html' | 'marp';
|
|
16
17
|
failClosedContext?: boolean;
|
|
17
18
|
extraContext?: string;
|
|
18
19
|
config?: Record<string, any>;
|
package/dist/index.cjs
CHANGED
|
@@ -5432,6 +5432,54 @@ ${input.languageDirective}
|
|
|
5432
5432
|
|
|
5433
5433
|
${input.headingDirective}`.trim();
|
|
5434
5434
|
}
|
|
5435
|
+
function buildHtmlDeckSlidePrompt(input) {
|
|
5436
|
+
const contract = input.customContract || `## HTML SLIDE ENGINE \u2014 AGENT GENERATION CONTRACT
|
|
5437
|
+
You generate structured slide decks for the LearnWell HTML Slide Presentation Engine.
|
|
5438
|
+
Your output MUST be a single, valid JSON object matching the Slide Deck JSON schema below.
|
|
5439
|
+
|
|
5440
|
+
### \u{1F3A8} Available Layout Presets (Use layoutId):
|
|
5441
|
+
1. **hero-cover**: Title/Cover slide with title, subtitle, presenter, date, tag.
|
|
5442
|
+
2. **two-column-split**: Side-by-side comparison (col1Title, col1Items[], col2Title, col2Items[]).
|
|
5443
|
+
3. **code-explainer**: Code walkthrough with filename, language, code, highlightLines, annotations[].
|
|
5444
|
+
4. **metrics-3-card**: 3 key stat cards (card1Title, card1Val, card1Desc, card2..., card3...).
|
|
5445
|
+
5. **process-flow**: Step-by-step pipeline (steps: [{ label, desc, status }]).
|
|
5446
|
+
6. **quiz-checkpoint**: Quick multiple choice question (question, options[], answerIdx, explanation).
|
|
5447
|
+
7. **tiered-practice-3cards**: Differentiated tiers (foundation, standard, challenge cards).
|
|
5448
|
+
8. **takeaways-summary**: Summary review with bullet takeaways.
|
|
5449
|
+
|
|
5450
|
+
### \u{1F399}\uFE0F Mandatory 3-Part Presenter Notes on EVERY slide:
|
|
5451
|
+
Every slide MUST include notes with:
|
|
5452
|
+
- Talk Track: 2-3 sentences speaking script
|
|
5453
|
+
- Cold-Call: 1 check question
|
|
5454
|
+
- Scaffolding Tip: 1 analogy or hint
|
|
5455
|
+
|
|
5456
|
+
### Output JSON Format:
|
|
5457
|
+
\`\`\`json
|
|
5458
|
+
{
|
|
5459
|
+
"title": "${input.lessonTitle}",
|
|
5460
|
+
"theme": "ocean",
|
|
5461
|
+
"slides": [
|
|
5462
|
+
{
|
|
5463
|
+
"layoutId": "hero-cover",
|
|
5464
|
+
"slots": { "title": "${input.lessonTitle}", "subtitle": "..." },
|
|
5465
|
+
"notes": "Talk Track: ...\\nCold-Call: ...\\nScaffolding Tip: ..."
|
|
5466
|
+
}
|
|
5467
|
+
]
|
|
5468
|
+
}
|
|
5469
|
+
\`\`\``;
|
|
5470
|
+
return `You are @illustrator & @content (Interactive HTML Slide Deck Presentation Architects).
|
|
5471
|
+
Based on Master Lesson Plan \`LESSON_${input.lessonCode}.md\`, pedagogical model (${input.pedagogyLabel}), and the HTML SLIDE ENGINE CONTRACT below, author the complete, highly engaging HTML presentation deck in JSON format: \`SLIDE_${input.lessonCode}\`.
|
|
5472
|
+
|
|
5473
|
+
${contract}
|
|
5474
|
+
|
|
5475
|
+
${input.languageDirective}
|
|
5476
|
+
|
|
5477
|
+
${input.headingDirective}${input.glossaryBlock ? `
|
|
5478
|
+
|
|
5479
|
+
${input.glossaryBlock}` : ""}
|
|
5480
|
+
|
|
5481
|
+
Output ONLY the raw JSON object. Do not include extra conversational text or markdown code fences.`.trim();
|
|
5482
|
+
}
|
|
5435
5483
|
|
|
5436
5484
|
// src/ai/prompts/teacherGuidePrompt.ts
|
|
5437
5485
|
function buildTeacherGuidePrompt(input) {
|
|
@@ -12462,46 +12510,175 @@ ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
|
|
|
12462
12510
|
const slideRelPath = `_content/${unitCode}/SLIDE_${lessonCode}.md`;
|
|
12463
12511
|
if (artifactScope.includes("SLIDE") && (!await storage.readArtifact(projectId, slideRelPath) || force)) {
|
|
12464
12512
|
onProgress?.("@illustrator", `[4/4] Authoring Presentation Slide Deck: \`SLIDE_${lessonCode}.md\`...`);
|
|
12465
|
-
const
|
|
12466
|
-
|
|
12513
|
+
const isHtmlEngine = options.slidesEngine === "html";
|
|
12514
|
+
if (isHtmlEngine) {
|
|
12515
|
+
let presentationKitAi = null;
|
|
12516
|
+
try {
|
|
12517
|
+
presentationKitAi = await import('@thanh01.pmt/presentation-kit/ai');
|
|
12518
|
+
} catch {
|
|
12519
|
+
}
|
|
12520
|
+
const slidePrompt = buildHtmlDeckSlidePrompt({
|
|
12521
|
+
lessonCode,
|
|
12522
|
+
lessonTitle,
|
|
12523
|
+
pedagogyLabel,
|
|
12524
|
+
languageDirective,
|
|
12525
|
+
headingDirective: buildHeadingDirective("SLIDE", slcMarkdown, targetLang),
|
|
12526
|
+
glossaryBlock: glossaryContext ? `[GLOSSARY TERMS (use these exact definitions)]:
|
|
12527
|
+
${glossaryContext}` : void 0,
|
|
12528
|
+
customContract: presentationKitAi?.SLIDE_HTML_PROMPT_CONTRACT
|
|
12529
|
+
});
|
|
12530
|
+
const rawSlide = await runCurriculumAIInference(
|
|
12531
|
+
[{ role: "user", content: slidePrompt }],
|
|
12532
|
+
satelliteContext,
|
|
12533
|
+
{},
|
|
12534
|
+
(chunk, type) => {
|
|
12535
|
+
options.onProgress?.("@illustrator", chunk, { type: type || "content", artifactType: "SLIDE" });
|
|
12536
|
+
}
|
|
12537
|
+
);
|
|
12538
|
+
if (!rawSlide || rawSlide.startsWith("\u26A0\uFE0F") || rawSlide.length < 200) {
|
|
12539
|
+
throw createAiInferenceError({
|
|
12540
|
+
errorCode: "ERR_AI_RESPONSE_MALFORMED",
|
|
12541
|
+
agent: "@illustrator",
|
|
12542
|
+
artifactType: "SLIDE",
|
|
12543
|
+
lessonId: lessonCode,
|
|
12544
|
+
message: `Agent @illustrator failed to author valid HTML Slides for ${lessonCode}.`,
|
|
12545
|
+
rawError: rawSlide || "Empty AI response"
|
|
12546
|
+
});
|
|
12547
|
+
}
|
|
12548
|
+
let deckJson = null;
|
|
12549
|
+
const extractCleanJson = (str) => {
|
|
12550
|
+
const fenceMatch = str.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
|
|
12551
|
+
const candidate = fenceMatch ? fenceMatch[1] : str;
|
|
12552
|
+
return candidate.trim();
|
|
12553
|
+
};
|
|
12554
|
+
try {
|
|
12555
|
+
deckJson = JSON.parse(extractCleanJson(rawSlide));
|
|
12556
|
+
} catch {
|
|
12557
|
+
try {
|
|
12558
|
+
const { jsonrepair: jsonrepair2 } = await import('jsonrepair');
|
|
12559
|
+
deckJson = JSON.parse(jsonrepair2(extractCleanJson(rawSlide)));
|
|
12560
|
+
} catch {
|
|
12561
|
+
}
|
|
12562
|
+
}
|
|
12563
|
+
let validation = presentationKitAi?.validateHtmlSlideDeck ? presentationKitAi.validateHtmlSlideDeck(deckJson, true) : deckJson && Array.isArray(deckJson.slides) ? { valid: true, score: 95, issues: [], slideCount: deckJson.slides.length, notesCoveragePercent: 100 } : { valid: false, score: 0, issues: [{ message: "Malformed JSON slide deck" }], slideCount: 0, notesCoveragePercent: 0 };
|
|
12564
|
+
if (!validation.valid && presentationKitAi?.validateHtmlSlideDeck) {
|
|
12565
|
+
const repairIssues = (validation.issues || []).map((i) => `- Slide ${i.slideIndex ?? "?"}: ${i.message}`).join("\n");
|
|
12566
|
+
onProgress?.("@illustrator", `\u26A0\uFE0F HTML slide deck failed schema validation \u2014 retrying once with targeted repair feedback...`);
|
|
12567
|
+
const repairPrompt = `Your previous slide deck failed strict schema validation:
|
|
12568
|
+
${repairIssues}
|
|
12569
|
+
|
|
12570
|
+
Fix ALL issues and output the complete corrected JSON object strictly matching the schema:`;
|
|
12571
|
+
const repairedRaw = await runCurriculumAIInference(
|
|
12572
|
+
[{ role: "user", content: repairPrompt }],
|
|
12573
|
+
satelliteContext,
|
|
12574
|
+
{},
|
|
12575
|
+
(chunk, type) => {
|
|
12576
|
+
options.onProgress?.("@illustrator", chunk, { type: type || "content", artifactType: "SLIDE" });
|
|
12577
|
+
}
|
|
12578
|
+
);
|
|
12579
|
+
try {
|
|
12580
|
+
deckJson = JSON.parse(extractCleanJson(repairedRaw));
|
|
12581
|
+
validation = presentationKitAi.validateHtmlSlideDeck(deckJson, true);
|
|
12582
|
+
} catch {
|
|
12583
|
+
try {
|
|
12584
|
+
const { jsonrepair: jsonrepair2 } = await import('jsonrepair');
|
|
12585
|
+
deckJson = JSON.parse(jsonrepair2(extractCleanJson(repairedRaw)));
|
|
12586
|
+
validation = presentationKitAi.validateHtmlSlideDeck(deckJson, true);
|
|
12587
|
+
} catch {
|
|
12588
|
+
}
|
|
12589
|
+
}
|
|
12590
|
+
}
|
|
12591
|
+
const markdownWrapper = `---
|
|
12592
|
+
id: "SLIDE_${lessonCode}"
|
|
12593
|
+
title: "${titleHeader(lessonTitle)}"
|
|
12594
|
+
type: "SLIDE"
|
|
12595
|
+
format: "html-deck"
|
|
12596
|
+
engine: "html"
|
|
12597
|
+
phase: "P2"
|
|
12598
|
+
deliverable: "P2-T09"
|
|
12599
|
+
version: "v1.0"
|
|
12600
|
+
date: "${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}"
|
|
12601
|
+
---
|
|
12602
|
+
|
|
12603
|
+
\`\`\`json
|
|
12604
|
+
${JSON.stringify(deckJson || {}, null, 2)}
|
|
12605
|
+
\`\`\`
|
|
12606
|
+
`;
|
|
12607
|
+
await storage.saveArtifact(projectId, slideRelPath, markdownWrapper);
|
|
12608
|
+
producedArtifacts.push(`SLIDE_${lessonCode}.md`);
|
|
12609
|
+
if (deckJson) {
|
|
12610
|
+
const deckJsonStr = JSON.stringify(deckJson, null, 2);
|
|
12611
|
+
await storage.saveArtifact(projectId, `_content/${unitCode}/SLIDE_${lessonCode}.deck.json`, deckJsonStr);
|
|
12612
|
+
producedArtifacts.push(`SLIDE_${lessonCode}.deck.json`);
|
|
12613
|
+
if (presentationKitAi?.compileHtmlDeck) {
|
|
12614
|
+
try {
|
|
12615
|
+
const compiled = presentationKitAi.compileHtmlDeck(deckJson);
|
|
12616
|
+
if (compiled?.html) {
|
|
12617
|
+
await storage.saveArtifact(projectId, `_content/${unitCode}/SLIDE_${lessonCode}.html`, compiled.html);
|
|
12618
|
+
producedArtifacts.push(`SLIDE_${lessonCode}.html`);
|
|
12619
|
+
}
|
|
12620
|
+
} catch (compErr) {
|
|
12621
|
+
console.warn(`[produceSingleLesson] Failed compiling HTML deck for ${lessonCode}:`, compErr);
|
|
12622
|
+
}
|
|
12623
|
+
}
|
|
12624
|
+
}
|
|
12625
|
+
const passed = Boolean(validation.valid && (validation.score ?? 100) >= 80);
|
|
12626
|
+
const score = validation.score ?? (passed ? 95 : 50);
|
|
12627
|
+
await storage.updateArtifactState(projectId, lessonCode, "SLIDE", {
|
|
12628
|
+
state: passed ? "approved" : "rejected",
|
|
12629
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12630
|
+
contentHash: computeContentHash(markdownWrapper),
|
|
12631
|
+
review: {
|
|
12632
|
+
decision: passed ? "APPROVED" : "NEEDS_REVISION",
|
|
12633
|
+
reviewedBy: "@agent-as-judge",
|
|
12634
|
+
reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12635
|
+
score,
|
|
12636
|
+
critique: passed ? `HTML Slide Deck passed strict schema validation (${score}/100, ${validation.slideCount ?? deckJson?.slides?.length ?? 0} slides). Auto-approved.` : `HTML Slide Deck failed schema validation: ${(validation.issues || []).map((i) => i.message).join("; ")}`
|
|
12637
|
+
}
|
|
12638
|
+
});
|
|
12639
|
+
onProgress?.("@reviewer", passed ? `\u2705 SLIDE judge PASS (${score}/100) [html-deck schema validated]` : `\u26A0\uFE0F SLIDE judge NEEDS_REVISION (${score}/100) [html-deck schema issues]`);
|
|
12640
|
+
} else {
|
|
12641
|
+
const canonicalSlideTemplate = loadCurriculumTemplate("SLIDE_template.md");
|
|
12642
|
+
const templateScaffold = canonicalSlideTemplate || `---
|
|
12467
12643
|
marp: true
|
|
12468
12644
|
theme: default
|
|
12469
12645
|
paginate: true
|
|
12470
12646
|
header: "${titleHeader(lessonTitle)}"
|
|
12471
12647
|
footer: "Curriculum OS \u2022 ${lessonCode} (${pedagogyLabel})"
|
|
12472
12648
|
---`;
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
|
|
12481
|
-
|
|
12482
|
-
|
|
12483
|
-
|
|
12484
|
-
|
|
12649
|
+
const slidePrompt = buildMarpMarkdownSlidePrompt({
|
|
12650
|
+
lessonCode,
|
|
12651
|
+
templateScaffold,
|
|
12652
|
+
languageDirective,
|
|
12653
|
+
headingDirective: buildHeadingDirective("SLIDE", slcMarkdown, targetLang)
|
|
12654
|
+
});
|
|
12655
|
+
const rawSlide = await runCurriculumAIInference(
|
|
12656
|
+
[{ role: "user", content: slidePrompt }],
|
|
12657
|
+
satelliteContext,
|
|
12658
|
+
{},
|
|
12659
|
+
(chunk, type) => {
|
|
12660
|
+
options.onProgress?.("@illustrator", chunk, { type: type || "content", artifactType: "SLIDE" });
|
|
12661
|
+
}
|
|
12662
|
+
);
|
|
12663
|
+
if (!rawSlide || rawSlide.startsWith("\u26A0\uFE0F") || rawSlide.length < 200) {
|
|
12664
|
+
throw createAiInferenceError({
|
|
12665
|
+
errorCode: "ERR_AI_RESPONSE_MALFORMED",
|
|
12666
|
+
agent: "@illustrator",
|
|
12667
|
+
artifactType: "SLIDE",
|
|
12668
|
+
lessonId: lessonCode,
|
|
12669
|
+
message: `Agent @illustrator failed to author valid Slides for ${lessonCode}.`,
|
|
12670
|
+
rawError: rawSlide || "Empty AI response"
|
|
12671
|
+
});
|
|
12485
12672
|
}
|
|
12486
|
-
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
artifactType: "SLIDE",
|
|
12492
|
-
lessonId: lessonCode,
|
|
12493
|
-
message: `Agent @illustrator failed to author valid Slides for ${lessonCode}.`,
|
|
12494
|
-
rawError: rawSlide || "Empty AI response"
|
|
12673
|
+
await storage.saveArtifact(projectId, slideRelPath, rawSlide);
|
|
12674
|
+
await storage.updateArtifactState(projectId, lessonCode, "SLIDE", {
|
|
12675
|
+
state: "completed",
|
|
12676
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12677
|
+
contentHash: computeContentHash(rawSlide)
|
|
12495
12678
|
});
|
|
12679
|
+
producedArtifacts.push(`SLIDE_${lessonCode}.md`);
|
|
12680
|
+
await judgeSat("SLIDE", rawSlide);
|
|
12496
12681
|
}
|
|
12497
|
-
await storage.saveArtifact(projectId, slideRelPath, rawSlide);
|
|
12498
|
-
await storage.updateArtifactState(projectId, lessonCode, "SLIDE", {
|
|
12499
|
-
state: "completed",
|
|
12500
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12501
|
-
contentHash: computeContentHash(rawSlide)
|
|
12502
|
-
});
|
|
12503
|
-
producedArtifacts.push(`SLIDE_${lessonCode}.md`);
|
|
12504
|
-
await judgeSat("SLIDE", rawSlide);
|
|
12505
12682
|
}
|
|
12506
12683
|
const guideRelPath = `_content/${unitCode}/GUIDE_${lessonCode}.md`;
|
|
12507
12684
|
if (artifactScope.includes("GUIDE") && (!await storage.readArtifact(projectId, guideRelPath) || force)) {
|
|
@@ -13444,6 +13621,24 @@ function getArtifactSpecializedInvariants(type, req) {
|
|
|
13444
13621
|
const studentCount = req.studentCount || "25";
|
|
13445
13622
|
switch (type) {
|
|
13446
13623
|
case "slide": {
|
|
13624
|
+
if (req.slidesEngine === "html") {
|
|
13625
|
+
return `
|
|
13626
|
+
### \u{1F3AC} INTERACTIVE HTML SLIDE ENGINE CONTRACT:
|
|
13627
|
+
You generate structured slide decks for the LearnWell HTML Slide Presentation Engine.
|
|
13628
|
+
Output a single valid JSON object matching: { "title": "...", "theme": "ocean", "slides": [{ "layoutId": "hero-cover", "slots": { ... }, "notes": "..." }] }
|
|
13629
|
+
|
|
13630
|
+
Layout Presets available:
|
|
13631
|
+
- hero-cover (title, subtitle, presenter, date, tag)
|
|
13632
|
+
- two-column-split (col1Title, col1Items[], col2Title, col2Items[])
|
|
13633
|
+
- code-explainer (filename, language, code, highlightLines, annotations[])
|
|
13634
|
+
- metrics-3-card (card1Title, card1Val, card1Desc, ...)
|
|
13635
|
+
- process-flow (steps: [{ label, desc, status }])
|
|
13636
|
+
- quiz-checkpoint (question, options[], answerIdx, explanation)
|
|
13637
|
+
- tiered-practice-3cards (foundation, standard, challenge cards)
|
|
13638
|
+
- takeaways-summary (takeaways: bullet points)
|
|
13639
|
+
|
|
13640
|
+
Mandatory Presenter Notes on every slide with Talk Track, Cold-Call, and Scaffolding Tip.`;
|
|
13641
|
+
}
|
|
13447
13642
|
const slideCount = cfg.slideCount || 10;
|
|
13448
13643
|
const presentationStyle = cfg.presentationStyle || "modern";
|
|
13449
13644
|
const presentationDuration = cfg.presentationDuration || 45;
|
|
@@ -17524,6 +17719,7 @@ exports.buildExpositionExcerpt = buildExpositionExcerpt;
|
|
|
17524
17719
|
exports.buildExtensionPrompt = buildExtensionPrompt;
|
|
17525
17720
|
exports.buildHandoutPrompt = buildHandoutPrompt;
|
|
17526
17721
|
exports.buildHeadingDirective = buildHeadingDirective;
|
|
17722
|
+
exports.buildHtmlDeckSlidePrompt = buildHtmlDeckSlidePrompt;
|
|
17527
17723
|
exports.buildImagePrompt = buildImagePrompt;
|
|
17528
17724
|
exports.buildJudgePrompt = buildJudgePrompt;
|
|
17529
17725
|
exports.buildLanguageDirective = buildLanguageDirective;
|