@thanh01.pmt/curriculum-kit 1.4.50 → 1.4.51
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 +47 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.mjs +47 -7
- package/dist/index.mjs.map +1 -1
- package/dist/workflow/index.cjs.map +1 -1
- package/dist/workflow/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -11072,6 +11072,15 @@ function cutBackToCheckpoint(current, nodeById, spec, warnings) {
|
|
|
11072
11072
|
current.nodeIds = current.entries.map((e) => e.id);
|
|
11073
11073
|
return displacedEntries.map((e) => nodeById.get(e.id)).filter((n) => n != null);
|
|
11074
11074
|
}
|
|
11075
|
+
function canCoalesceWithinZpdBudget(curr, next, nodeById, maxNew) {
|
|
11076
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11077
|
+
for (const s of [curr, next]) {
|
|
11078
|
+
for (const nid of s.nodeIds) {
|
|
11079
|
+
for (const c of nodeById.get(nid)?.concept_codes || []) seen.add(c);
|
|
11080
|
+
}
|
|
11081
|
+
}
|
|
11082
|
+
return seen.size <= maxNew;
|
|
11083
|
+
}
|
|
11075
11084
|
function packUnitSessions(group, nodeById, spec, warnings) {
|
|
11076
11085
|
const sessions = [];
|
|
11077
11086
|
const fresh = () => ({ groupId: group.key, nodeIds: [], entries: [], knowledgeMinutes: 0, practiceMinutes: 0, oversized: false });
|
|
@@ -11295,10 +11304,10 @@ function checkSessionZpd(sessionIndex, nodeIds, nodeById, allSeenConcepts, allSe
|
|
|
11295
11304
|
}
|
|
11296
11305
|
if (sessionIndex > 0) {
|
|
11297
11306
|
if (concepts.length > 1 && knownConcepts.length === 0) {
|
|
11298
|
-
verdict = "NO_ZPD_BRIDGE";
|
|
11307
|
+
if (verdict !== "TOO_MANY_NEW") verdict = "NO_ZPD_BRIDGE";
|
|
11299
11308
|
issues.push("No known concepts from previous sessions to bridge new learning");
|
|
11300
11309
|
} else if (concepts.length === 0 && allKeywords.length > 2 && knownKeywords.length === 0) {
|
|
11301
|
-
verdict = "NO_ZPD_BRIDGE";
|
|
11310
|
+
if (verdict !== "TOO_MANY_NEW") verdict = "NO_ZPD_BRIDGE";
|
|
11302
11311
|
issues.push("No known keywords from previous sessions to bridge new learning");
|
|
11303
11312
|
}
|
|
11304
11313
|
}
|
|
@@ -11507,7 +11516,8 @@ async function buildCurriculumPlan(rawGraph, options) {
|
|
|
11507
11516
|
const currMins = curr.knowledgeMinutes + curr.practiceMinutes;
|
|
11508
11517
|
const nextMins = next.knowledgeMinutes + next.practiceMinutes;
|
|
11509
11518
|
const totalContent = currMins + nextMins;
|
|
11510
|
-
|
|
11519
|
+
const maxNew = spec.maxNewConceptsPerSession ?? Infinity;
|
|
11520
|
+
if ((currMins <= 45 || nextMins <= 45 || totalContent <= spec.contentBudget * 1.5) && canCoalesceWithinZpdBudget(curr, next, nodeById, maxNew)) {
|
|
11511
11521
|
const scale = totalContent > spec.contentBudget ? spec.contentBudget / totalContent : 1;
|
|
11512
11522
|
curr.nodeIds.push(...next.nodeIds);
|
|
11513
11523
|
for (const e of next.entries) {
|
|
@@ -11576,9 +11586,13 @@ async function buildCurriculumPlan(rawGraph, options) {
|
|
|
11576
11586
|
if (options.llmFn) {
|
|
11577
11587
|
const sys = "You write ONE concise learning objective sentence (max 40 words) for a training session. Output the sentence only.";
|
|
11578
11588
|
const usr = "Session: " + lessonCode + " \u2014 " + nodeNames.join("; ") + ". Unit: " + unit.name + ". Course goals: " + (constraints.course_goals.join("; ") || "n/a") + ".";
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11589
|
+
try {
|
|
11590
|
+
const out = (await options.llmFn(sys, usr)).trim();
|
|
11591
|
+
if (out.length < 10) throw new Error("LLM prose objective too short for " + lessonCode + ': "' + out.slice(0, 40) + '"');
|
|
11592
|
+
proseObjective = out;
|
|
11593
|
+
} catch (e) {
|
|
11594
|
+
warnings.push("prose_objective_llm_failed:" + (e instanceof Error ? e.message.slice(0, 80) : String(e).slice(0, 80)));
|
|
11595
|
+
}
|
|
11582
11596
|
}
|
|
11583
11597
|
const ctx = { lessonCode, sessionIndex: i, nodeIds: s.nodeIds, packedMinutes: s.knowledgeMinutes + s.practiceMinutes, contentBudget: spec.contentBudget };
|
|
11584
11598
|
const nodeKeywords = (ids) => [...new Set(ids.flatMap((id) => nodeById.get(id).keywords))];
|
|
@@ -11676,6 +11690,32 @@ ${sessionSummaries}`;
|
|
|
11676
11690
|
warnings.push("differentiation_llm_failed:" + (e instanceof Error ? e.message.slice(0, 80) : String(e).slice(0, 80)));
|
|
11677
11691
|
}
|
|
11678
11692
|
}
|
|
11693
|
+
if (options.llmFn && sessions.length > 0) {
|
|
11694
|
+
try {
|
|
11695
|
+
const eSys = 'You write OBSERVABLE exit evidence for curriculum sessions. Output ONLY a JSON object mapping session-id to an array of 1-3 short strings. Each string must name what a bystander can SEE or VERIFY at the end of the session: a running screen, a passing test, a saved file, correct printed output, a working interaction. NEVER write "Student understands/explains/applies X" \u2014 describe the artifact or observable result instead. Same language as the session objectives.';
|
|
11696
|
+
const eUsr = `Age band: ${constraints.age_band[0]}-${constraints.age_band[1]}. Entry level: ${constraints.entry_level}.
|
|
11697
|
+
Sessions (current exit evidence to improve):
|
|
11698
|
+
${sessions.map((s) => `${s.id}|objective: ${s.prose_objective.slice(0, 100)}|current: ${s.exit_evidence.join(" ; ")}`).join("\n")}`;
|
|
11699
|
+
const raw = (await options.llmFn(eSys, eUsr)).trim();
|
|
11700
|
+
const match = raw.match(/\{[\s\S]*\}/);
|
|
11701
|
+
if (match) {
|
|
11702
|
+
const parsed = JSON.parse(match[0]);
|
|
11703
|
+
let upgraded = 0;
|
|
11704
|
+
for (const s of sessions) {
|
|
11705
|
+
const arr = parsed[s.id];
|
|
11706
|
+
if (Array.isArray(arr) && arr.length > 0 && arr.every((x) => typeof x === "string" && x.trim().length >= 8)) {
|
|
11707
|
+
s.exit_evidence = arr.map((x) => x.trim());
|
|
11708
|
+
upgraded++;
|
|
11709
|
+
}
|
|
11710
|
+
}
|
|
11711
|
+
if (upgraded < sessions.length) warnings.push(`exit_evidence_llm_partial:${upgraded}/${sessions.length}`);
|
|
11712
|
+
} else {
|
|
11713
|
+
warnings.push("exit_evidence_llm_unparseable");
|
|
11714
|
+
}
|
|
11715
|
+
} catch (e) {
|
|
11716
|
+
warnings.push("exit_evidence_llm_failed:" + (e instanceof Error ? e.message.slice(0, 80) : String(e).slice(0, 80)));
|
|
11717
|
+
}
|
|
11718
|
+
}
|
|
11679
11719
|
const glossaryScope = sessions.map((s) => ({
|
|
11680
11720
|
session_id: s.id,
|
|
11681
11721
|
terms: [...new Set(s.node_ids.flatMap((id) => nodeById.get(id).keywords))]
|
|
@@ -31997,6 +32037,7 @@ exports.buildStandardsContextBlock = buildStandardsContextBlock;
|
|
|
31997
32037
|
exports.buildTeacherGuidePrompt = buildTeacherGuidePrompt;
|
|
31998
32038
|
exports.buildWalkingSkeleton = buildWalkingSkeleton;
|
|
31999
32039
|
exports.buildWorksheetPrompt = buildWorksheetPrompt;
|
|
32040
|
+
exports.canCoalesceWithinZpdBudget = canCoalesceWithinZpdBudget;
|
|
32000
32041
|
exports.checkSessionZpd = checkSessionZpd;
|
|
32001
32042
|
exports.classifyDepthCandidates = classifyDepthCandidates;
|
|
32002
32043
|
exports.closeTruncatedJson = closeTruncatedJson;
|