@thanh01.pmt/curriculum-kit 1.0.10 → 1.0.12
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/index.cjs +124 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -4
- package/dist/index.d.ts +7 -4
- package/dist/index.mjs +124 -35
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -13549,7 +13549,7 @@ function safeParseJson(rawText) {
|
|
|
13549
13549
|
return null;
|
|
13550
13550
|
}
|
|
13551
13551
|
}
|
|
13552
|
-
async function streamLLMWithFallback(systemPrompt, userPrompt, apiKeys = {}, onChunk) {
|
|
13552
|
+
async function streamLLMWithFallback(systemPrompt, userPrompt, apiKeys = {}, onChunk, preferredModel, preferredProvider) {
|
|
13553
13553
|
const alibabaKey = apiKeys.alibaba || apiKeys.dashscope || process.env.ALIBABA_API_KEY || process.env.DASHSCOPE_API_KEY;
|
|
13554
13554
|
const nvidiaKey = apiKeys.nvidia || process.env.NVIDIA_API_KEY;
|
|
13555
13555
|
const deepseekKey = apiKeys.deepseek || process.env.DEEPSEEK_API_KEY;
|
|
@@ -13557,6 +13557,11 @@ async function streamLLMWithFallback(systemPrompt, userPrompt, apiKeys = {}, onC
|
|
|
13557
13557
|
const geminiKey = apiKeys.gemini || process.env.GEMINI_API_KEY;
|
|
13558
13558
|
const openrouterPreset = process.env.OPENROUTER_FREE_PRESET || "@preset/coding-free";
|
|
13559
13559
|
const candidates = [];
|
|
13560
|
+
if (preferredModel) {
|
|
13561
|
+
const prov = preferredProvider || "openrouter";
|
|
13562
|
+
const key = apiKeys[prov] || (prov === "openrouter" ? openrouterKey : prov === "nvidia" ? nvidiaKey : prov === "alibaba" ? alibabaKey : geminiKey) || "";
|
|
13563
|
+
candidates.push({ provider: prov, model: preferredModel, apiKey: key });
|
|
13564
|
+
}
|
|
13560
13565
|
if (openrouterKey && isProviderEnabled("openrouter")) {
|
|
13561
13566
|
const orModels = [
|
|
13562
13567
|
openrouterPreset,
|
|
@@ -13564,40 +13569,49 @@ async function streamLLMWithFallback(systemPrompt, userPrompt, apiKeys = {}, onC
|
|
|
13564
13569
|
"nvidia/nemotron-3-super-120b-a12b:free",
|
|
13565
13570
|
"nvidia/nemotron-3-ultra-550b-a55b:free",
|
|
13566
13571
|
"nvidia/nemotron-3.5-lightning:free",
|
|
13567
|
-
"minimax/minimax-m3:free",
|
|
13568
13572
|
"cohere/north-mini-code:free"
|
|
13569
13573
|
].filter((m) => isModelAllowed(m));
|
|
13570
13574
|
for (const m of Array.from(new Set(orModels))) {
|
|
13571
|
-
candidates.
|
|
13575
|
+
if (!candidates.some((c) => c.provider === "openrouter" && c.model === m)) {
|
|
13576
|
+
candidates.push({ provider: "openrouter", model: m, apiKey: openrouterKey });
|
|
13577
|
+
}
|
|
13572
13578
|
}
|
|
13573
13579
|
}
|
|
13574
13580
|
if (nvidiaKey && isProviderEnabled("nvidia")) {
|
|
13575
13581
|
const nemotronModels = [
|
|
13576
|
-
"nvidia/nemotron-3-ultra-550b-a55b
|
|
13582
|
+
"nvidia/nemotron-3-ultra-550b-a55b",
|
|
13577
13583
|
"nvidia/nemotron-3.5-lightning-30b-a3b",
|
|
13578
13584
|
"nvidia/nemotron-3-super-120b-a12b",
|
|
13579
13585
|
"nvidia/llama-3.1-nemotron-70b-instruct"
|
|
13580
13586
|
].filter((m) => isModelAllowed(m));
|
|
13581
13587
|
for (const m of nemotronModels) {
|
|
13582
|
-
candidates.
|
|
13588
|
+
if (!candidates.some((c) => c.provider === "nvidia" && c.model === m)) {
|
|
13589
|
+
candidates.push({ provider: "nvidia", model: m, apiKey: nvidiaKey });
|
|
13590
|
+
}
|
|
13583
13591
|
}
|
|
13584
13592
|
}
|
|
13585
13593
|
if (alibabaKey && isProviderEnabled("alibaba")) {
|
|
13586
13594
|
const aliModels = ["qwen-plus", "qwen-turbo", "qwen3.7-plus"].filter((m) => isModelAllowed(m));
|
|
13587
13595
|
for (const m of aliModels) {
|
|
13588
|
-
candidates.
|
|
13596
|
+
if (!candidates.some((c) => c.provider === "alibaba" && c.model === m)) {
|
|
13597
|
+
candidates.push({ provider: "alibaba", model: m, apiKey: alibabaKey });
|
|
13598
|
+
}
|
|
13589
13599
|
}
|
|
13590
13600
|
}
|
|
13591
13601
|
if (deepseekKey && isProviderEnabled("deepseek")) {
|
|
13592
13602
|
const dsModels = ["deepseek-chat", "deepseek-coder"].filter((m) => isModelAllowed(m));
|
|
13593
13603
|
for (const m of dsModels) {
|
|
13594
|
-
candidates.
|
|
13604
|
+
if (!candidates.some((c) => c.provider === "deepseek" && c.model === m)) {
|
|
13605
|
+
candidates.push({ provider: "deepseek", model: m, apiKey: deepseekKey });
|
|
13606
|
+
}
|
|
13595
13607
|
}
|
|
13596
13608
|
}
|
|
13597
13609
|
if (geminiKey && (isProviderEnabled("gemini") || isProviderEnabled("google"))) {
|
|
13598
13610
|
const gModels = ["gemini-1.5-flash", "gemini-2.0-flash", "gemini-1.5-pro"].filter((m) => isModelAllowed(m));
|
|
13599
13611
|
for (const m of gModels) {
|
|
13600
|
-
candidates.
|
|
13612
|
+
if (!candidates.some((c) => c.provider === "google" && c.model === m)) {
|
|
13613
|
+
candidates.push({ provider: "google", model: m, apiKey: geminiKey });
|
|
13614
|
+
}
|
|
13601
13615
|
}
|
|
13602
13616
|
}
|
|
13603
13617
|
const fallbackChain = getDesignatedFallbackChain();
|
|
@@ -13626,15 +13640,27 @@ THINKING DIRECTIVE: Keep reasoning concise, structured, and focused strictly on
|
|
|
13626
13640
|
system: systemInstructions,
|
|
13627
13641
|
prompt: userPrompt,
|
|
13628
13642
|
temperature: 0.2,
|
|
13629
|
-
|
|
13643
|
+
includeRawChunks: true,
|
|
13644
|
+
abortSignal: AbortSignal.timeout(6e4)
|
|
13630
13645
|
});
|
|
13631
13646
|
let fullContent = "";
|
|
13632
13647
|
for await (const part of streamResult.fullStream) {
|
|
13633
13648
|
if (part.type === "reasoning-delta") {
|
|
13634
|
-
|
|
13649
|
+
const thoughtText = part.text ?? part.delta ?? "";
|
|
13650
|
+
if (thoughtText) onChunk?.(thoughtText, "thought");
|
|
13651
|
+
} else if (part.type === "raw") {
|
|
13652
|
+
const raw = part.rawValue;
|
|
13653
|
+
const delta = raw?.choices?.[0]?.delta;
|
|
13654
|
+
const reasoning = delta?.reasoning_content || delta?.reasoning;
|
|
13655
|
+
if (reasoning) {
|
|
13656
|
+
onChunk?.(reasoning, "thought");
|
|
13657
|
+
}
|
|
13635
13658
|
} else if (part.type === "text-delta") {
|
|
13636
|
-
|
|
13637
|
-
|
|
13659
|
+
const textDelta = part.text ?? part.delta ?? "";
|
|
13660
|
+
if (textDelta) {
|
|
13661
|
+
fullContent += textDelta;
|
|
13662
|
+
onChunk?.(textDelta, "content");
|
|
13663
|
+
}
|
|
13638
13664
|
}
|
|
13639
13665
|
}
|
|
13640
13666
|
if (fullContent.trim()) {
|
|
@@ -13697,6 +13723,68 @@ Return concise JSON matching:
|
|
|
13697
13723
|
}
|
|
13698
13724
|
return parsedResearch;
|
|
13699
13725
|
}
|
|
13726
|
+
var CONTEXT_KEY_LABELS = {
|
|
13727
|
+
domain: "Domain",
|
|
13728
|
+
customDomain: "Custom Domain",
|
|
13729
|
+
context: "Educational Context (Tier)",
|
|
13730
|
+
contextLabel: "Educational Context",
|
|
13731
|
+
customContext: "Custom Educational Context",
|
|
13732
|
+
targetAgeTier: "Target Age Tier",
|
|
13733
|
+
targetAge: "Target Age & Audience",
|
|
13734
|
+
customAge: "Custom Age Group",
|
|
13735
|
+
courseDurationTier: "Course Duration Tier",
|
|
13736
|
+
courseDuration: "Planned Course Duration",
|
|
13737
|
+
customDuration: "Custom Course Duration",
|
|
13738
|
+
hardwareReadinessTier: "Hardware Readiness Tier",
|
|
13739
|
+
hardwareReadiness: "Hardware & Tool Readiness",
|
|
13740
|
+
customHardware: "Custom Hardware Setup",
|
|
13741
|
+
language: "Artifact Output Language",
|
|
13742
|
+
totalWeeks: "Total Weeks",
|
|
13743
|
+
sessionsPerWeek: "Sessions Per Week",
|
|
13744
|
+
sessionDurationMinutes: "Session Duration (minutes)",
|
|
13745
|
+
totalSessions: "Total Sessions",
|
|
13746
|
+
isConsecutiveSessions: "Consecutive (Block) Sessions",
|
|
13747
|
+
projectName: "Course Title",
|
|
13748
|
+
projectCode: "Project Identifier",
|
|
13749
|
+
courseDescription: "Idea Description"
|
|
13750
|
+
};
|
|
13751
|
+
var STRUCTURED_PROMPT_KEYS = /* @__PURE__ */ new Set([
|
|
13752
|
+
"projectName",
|
|
13753
|
+
"projectCode",
|
|
13754
|
+
"courseDescription",
|
|
13755
|
+
"language",
|
|
13756
|
+
"primaryGoal",
|
|
13757
|
+
"exitVision",
|
|
13758
|
+
"cognitiveDepth",
|
|
13759
|
+
"valueAndCertification",
|
|
13760
|
+
"entryBridge",
|
|
13761
|
+
"pedagogy",
|
|
13762
|
+
"classDynamic",
|
|
13763
|
+
"hardwareDeployment",
|
|
13764
|
+
"teacherRole",
|
|
13765
|
+
"lessonPacingModel",
|
|
13766
|
+
"voiceAndTone"
|
|
13767
|
+
]);
|
|
13768
|
+
function buildRemainingContextBlock(accumulatedData) {
|
|
13769
|
+
const lines = [];
|
|
13770
|
+
for (const [key, rawVal] of Object.entries(accumulatedData)) {
|
|
13771
|
+
if (STRUCTURED_PROMPT_KEYS.has(key)) continue;
|
|
13772
|
+
if (rawVal === void 0 || rawVal === null || rawVal === "") continue;
|
|
13773
|
+
if (key.endsWith("_ids") || key.endsWith("_id")) continue;
|
|
13774
|
+
const label = CONTEXT_KEY_LABELS[key] || key.replace(/([A-Z])/g, " $1").replace(/_/g, " ").replace(/^./, (c) => c.toUpperCase()).trim();
|
|
13775
|
+
let valueStr;
|
|
13776
|
+
if (Array.isArray(rawVal)) {
|
|
13777
|
+
valueStr = rawVal.map((v) => typeof v === "object" ? JSON.stringify(v) : String(v)).join("; ");
|
|
13778
|
+
} else if (typeof rawVal === "object") {
|
|
13779
|
+
valueStr = JSON.stringify(rawVal);
|
|
13780
|
+
} else {
|
|
13781
|
+
valueStr = String(rawVal);
|
|
13782
|
+
}
|
|
13783
|
+
if (!valueStr.trim()) continue;
|
|
13784
|
+
lines.push(`- ${label}: ${valueStr}`);
|
|
13785
|
+
}
|
|
13786
|
+
return lines.join("\n");
|
|
13787
|
+
}
|
|
13700
13788
|
async function streamLayerPrefillWithFallback(options, onChunk) {
|
|
13701
13789
|
const { action = "prefill", targetLayer = 1, accumulatedData = {}, apiKeys = {} } = options;
|
|
13702
13790
|
if (action === "research") {
|
|
@@ -13707,26 +13795,21 @@ async function streamLayerPrefillWithFallback(options, onChunk) {
|
|
|
13707
13795
|
projectName = "Curriculum Course",
|
|
13708
13796
|
projectCode = "curriculum-course",
|
|
13709
13797
|
courseDescription = "",
|
|
13710
|
-
domain = "tech",
|
|
13711
|
-
context = "center",
|
|
13712
|
-
contextLabel = "STEM Academy",
|
|
13713
13798
|
targetAgeTier = "secondary",
|
|
13714
13799
|
targetAge = "Secondary (Ages 11-15 / Grades 6-9)",
|
|
13715
13800
|
courseDurationTier = "standard",
|
|
13716
13801
|
courseDuration = "Standard Course (16-24 sessions / 24-36 hours)",
|
|
13717
|
-
hardwareReadinessTier = "none_budget",
|
|
13718
|
-
hardwareReadiness = "No dedicated hardware (Plug-and-play simulator or economical kit)",
|
|
13719
13802
|
primaryGoal = "",
|
|
13720
13803
|
exitVision = "",
|
|
13721
13804
|
valueAndCertification = "",
|
|
13722
|
-
|
|
13805
|
+
entryBridge = "",
|
|
13723
13806
|
pedagogy = "5E Instructional Model",
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13807
|
+
lessonPacingModel = "",
|
|
13808
|
+
voiceAndTone = "",
|
|
13809
|
+
classDynamic = "",
|
|
13810
|
+
hardwareDeployment = "",
|
|
13811
|
+
teacherRole = "",
|
|
13812
|
+
cognitiveDepth = "Apply"
|
|
13730
13813
|
} = accumulatedData;
|
|
13731
13814
|
const language = typeof options.language === "string" && options.language ? options.language : typeof accumulatedData.language === "string" && accumulatedData.language ? accumulatedData.language : "vi";
|
|
13732
13815
|
const textLangMandate = language === "vi" ? "natural, fluent Vietnamese (Ti\u1EBFng Vi\u1EC7t)" : language === "en" ? "natural, fluent English" : `natural, fluent ${language}`;
|
|
@@ -13762,7 +13845,7 @@ ${targetLayer === 1 ? `
|
|
|
13762
13845
|
- Field 2 (id: 'brandingAndTone', type: 'single_choice'): Art Direction & Visual Mood (ART_DIRECTION: Future Maker Lab high-contrast vs Clean Minimalist Studio vs Gamified Playful).
|
|
13763
13846
|
- Field 3 (id: 'differentiationStrategy', type: 'single_choice'): Differentiation & Scaffolding Strategy (CONTENT_STYLE_GUIDE: Tier 1/2/3 Bronze/Silver/Gold + EXT Challenges vs Open-ended Rubric Studio).
|
|
13764
13847
|
- Field 4 (id: 'cognitiveScaffolding', type: 'textarea'): Concrete scaffolding methods (Starter Code, color-coded breadboards, 4-step debug poster, simulator preview).
|
|
13765
|
-
- Field 5 (id: 'recommendedToolchain', type: 'single_choice'): 3 concrete toolchain/IDE options matching
|
|
13848
|
+
- Field 5 (id: 'recommendedToolchain', type: 'single_choice'): 3 concrete toolchain/IDE options matching the confirmed Hardware & Tool Readiness from FULL ACCUMULATED CONTEXT.
|
|
13766
13849
|
- Field 6 (id: 'artifactScope', type: 'multi_choice'): Deliverable artifacts (LESSON mandatory + ACT, QUIZ, SLIDE, WKS, HANDOUT, GUIDE, CODE).
|
|
13767
13850
|
- Field 7 (id: 'assessmentStrategy', type: 'single_choice'): Grading weights (e.g. 40% Formative Process + 60% Capstone Rubric).
|
|
13768
13851
|
`}
|
|
@@ -13792,10 +13875,8 @@ RETURN STRICT VALID JSON ONLY adhering exactly to this format:
|
|
|
13792
13875
|
- Course Title: "${projectName}"
|
|
13793
13876
|
- Project Identifier: "${projectCode}"
|
|
13794
13877
|
- Idea Description: "${courseDescription}"
|
|
13795
|
-
- Target Age & Audience: ${targetAge}
|
|
13796
|
-
- Planned Course Duration: ${courseDuration}
|
|
13797
|
-
- Hardware & Tool Readiness: ${hardwareReadiness} (Tier: ${hardwareReadinessTier})
|
|
13798
|
-
- Educational Context: ${contextLabel || context} | Domain: ${domain}
|
|
13878
|
+
- Target Age & Audience: ${targetAge}
|
|
13879
|
+
- Planned Course Duration: ${courseDuration}
|
|
13799
13880
|
|
|
13800
13881
|
${targetLayer >= 2 ? `
|
|
13801
13882
|
APPROVED PARAMETERS FROM LAYER 1 (STRATEGIC INTENT & OUTCOMES):
|
|
@@ -13803,17 +13884,23 @@ APPROVED PARAMETERS FROM LAYER 1 (STRATEGIC INTENT & OUTCOMES):
|
|
|
13803
13884
|
- Competency Exit Vision: "${exitVision}"
|
|
13804
13885
|
- Target Cognitive Depth: "${cognitiveDepth}"
|
|
13805
13886
|
- Value & Recognition: "${valueAndCertification}"
|
|
13887
|
+
- Prerequisite Entry Bridge: "${entryBridge}"
|
|
13806
13888
|
` : ""}
|
|
13807
13889
|
|
|
13808
13890
|
${targetLayer >= 3 ? `
|
|
13809
13891
|
APPROVED PARAMETERS FROM LAYER 2 (PEDAGOGY & LOGISTICS):
|
|
13810
|
-
-
|
|
13811
|
-
-
|
|
13812
|
-
-
|
|
13813
|
-
-
|
|
13892
|
+
- Lesson Pacing Model: "${lessonPacingModel}"
|
|
13893
|
+
- Selected Pedagogy Model: "${pedagogy}"
|
|
13894
|
+
- Voice & Tone: "${voiceAndTone}"
|
|
13895
|
+
- Class Dynamics / Hardware Ratio: "${classDynamic}"
|
|
13896
|
+
- Lab Deployment Mode: "${hardwareDeployment}"
|
|
13897
|
+
- Instructional Role: "${teacherRole}"
|
|
13814
13898
|
` : ""}
|
|
13815
13899
|
|
|
13816
|
-
|
|
13900
|
+
FULL ACCUMULATED CONTEXT (ALL CONFIRMED PARAMETERS FROM EVERY PREVIOUS STEP \u2014 user decisions, organization/instructor/template profiles, schedules and constraints; every line below MUST be honored in your output):
|
|
13901
|
+
${buildRemainingContextBlock(accumulatedData) || "(no additional context)"}
|
|
13902
|
+
|
|
13903
|
+
REQUIREMENT: Synthesize ALL parameters above \u2014 every single line in FULL ACCUMULATED CONTEXT is a confirmed user decision or system constraint and MUST influence the generated configuration. Produce the high-fidelity pre-fill configuration for LAYER ${targetLayer}.`;
|
|
13817
13904
|
let rawContent = "";
|
|
13818
13905
|
await streamLLMWithFallback(
|
|
13819
13906
|
systemPrompt,
|
|
@@ -13822,7 +13909,9 @@ REQUIREMENT: Synthesize all parameters above and produce the high-fidelity pre-f
|
|
|
13822
13909
|
(chunk, type) => {
|
|
13823
13910
|
if (type === "content") rawContent += chunk;
|
|
13824
13911
|
onChunk?.(chunk, type);
|
|
13825
|
-
}
|
|
13912
|
+
},
|
|
13913
|
+
options.model,
|
|
13914
|
+
options.provider
|
|
13826
13915
|
);
|
|
13827
13916
|
const parsed = safeParseJson(rawContent);
|
|
13828
13917
|
return {
|