@thanh01.pmt/curriculum-kit 1.0.6 → 1.0.8
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/LICENSE +21 -0
- package/dist/{index-BIhxrUEa.d.cts → index-BEicVaQ9.d.cts} +60 -5
- package/dist/{index-BvWC_xXe.d.ts → index-BfDHBO7f.d.ts} +60 -5
- package/dist/index.cjs +293 -234
- 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 +291 -215
- package/dist/index.mjs.map +1 -1
- package/dist/media/index.cjs +30 -0
- package/dist/media/index.cjs.map +1 -1
- package/dist/media/index.d.cts +10 -0
- package/dist/media/index.d.ts +10 -0
- package/dist/media/index.mjs +30 -0
- package/dist/media/index.mjs.map +1 -1
- package/dist/workflow/index.cjs +460 -47
- package/dist/workflow/index.cjs.map +1 -1
- package/dist/workflow/index.d.cts +2 -1
- package/dist/workflow/index.d.ts +2 -1
- package/dist/workflow/index.mjs +457 -27
- package/dist/workflow/index.mjs.map +1 -1
- package/package.json +20 -21
package/dist/workflow/index.cjs
CHANGED
|
@@ -7,7 +7,7 @@ var google = require('@ai-sdk/google');
|
|
|
7
7
|
var openai = require('@ai-sdk/openai');
|
|
8
8
|
var deepseek = require('@ai-sdk/deepseek');
|
|
9
9
|
var zod = require('zod');
|
|
10
|
-
var
|
|
10
|
+
var workflow = require('workflow');
|
|
11
11
|
var fs2 = require('fs/promises');
|
|
12
12
|
var rest = require('@octokit/rest');
|
|
13
13
|
var supabaseJs = require('@supabase/supabase-js');
|
|
@@ -17,27 +17,8 @@ require('crypto');
|
|
|
17
17
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
18
18
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
19
19
|
|
|
20
|
-
function _interopNamespace(e) {
|
|
21
|
-
if (e && e.__esModule) return e;
|
|
22
|
-
var n = Object.create(null);
|
|
23
|
-
if (e) {
|
|
24
|
-
Object.keys(e).forEach(function (k) {
|
|
25
|
-
if (k !== 'default') {
|
|
26
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
27
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
28
|
-
enumerable: true,
|
|
29
|
-
get: function () { return e[k]; }
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
n.default = e;
|
|
35
|
-
return Object.freeze(n);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
20
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
39
21
|
var path4__default = /*#__PURE__*/_interopDefault(path4);
|
|
40
|
-
var workflowPkg__namespace = /*#__PURE__*/_interopNamespace(workflowPkg);
|
|
41
22
|
var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
42
23
|
|
|
43
24
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -3885,7 +3866,7 @@ Respond with a valid JSON object matching the schema.`
|
|
|
3885
3866
|
async function withRateLimitBackoff(options) {
|
|
3886
3867
|
let attempt = 1;
|
|
3887
3868
|
try {
|
|
3888
|
-
const meta =
|
|
3869
|
+
const meta = workflow.getStepMetadata();
|
|
3889
3870
|
if (meta && typeof meta.attempt === "number") {
|
|
3890
3871
|
attempt = meta.attempt;
|
|
3891
3872
|
}
|
|
@@ -3901,7 +3882,7 @@ async function withRateLimitBackoff(options) {
|
|
|
3901
3882
|
if (isRateLimited || isTransientError) {
|
|
3902
3883
|
const retryAfterSeconds = Math.min(120, Math.pow(2, attempt) * 2);
|
|
3903
3884
|
const reason = isRateLimited ? "Rate limit exceeded (429)" : `Transient server error (${status || "network"})`;
|
|
3904
|
-
throw new
|
|
3885
|
+
throw new workflow.RetryableError(`[${options.stepName}] ${reason}. Retrying attempt ${attempt + 1}...`, {
|
|
3905
3886
|
retryAfter: `${retryAfterSeconds}s`
|
|
3906
3887
|
});
|
|
3907
3888
|
}
|
|
@@ -4975,14 +4956,14 @@ async function publishToSupabaseStep(options) {
|
|
|
4975
4956
|
|
|
4976
4957
|
// src/workflow/gateSettings.ts
|
|
4977
4958
|
var DEFAULT_GATE_SETTINGS = Object.freeze({
|
|
4978
|
-
LEARNER_PROFILE: "
|
|
4979
|
-
PROJECT_BRIEF: "
|
|
4980
|
-
REFERENCE_PACK: "
|
|
4981
|
-
CURRICULUM_FRAMEWORK: "
|
|
4982
|
-
KNOWLEDGE_EXPOSITION: "
|
|
4983
|
-
STYLE_GUIDE: "
|
|
4984
|
-
ART_DIRECTION: "
|
|
4985
|
-
LESSON: "
|
|
4959
|
+
LEARNER_PROFILE: "OFF",
|
|
4960
|
+
PROJECT_BRIEF: "OFF",
|
|
4961
|
+
REFERENCE_PACK: "OFF",
|
|
4962
|
+
CURRICULUM_FRAMEWORK: "OFF",
|
|
4963
|
+
KNOWLEDGE_EXPOSITION: "OFF",
|
|
4964
|
+
STYLE_GUIDE: "OFF",
|
|
4965
|
+
ART_DIRECTION: "OFF",
|
|
4966
|
+
LESSON: "OFF",
|
|
4986
4967
|
ACT: "OFF",
|
|
4987
4968
|
QUIZ: "OFF",
|
|
4988
4969
|
SLIDE: "OFF",
|
|
@@ -4990,7 +4971,7 @@ var DEFAULT_GATE_SETTINGS = Object.freeze({
|
|
|
4990
4971
|
WKS: "OFF",
|
|
4991
4972
|
HANDOUT: "OFF",
|
|
4992
4973
|
EXT: "OFF",
|
|
4993
|
-
CODE: "
|
|
4974
|
+
CODE: "OFF",
|
|
4994
4975
|
MEDIA_SCRIPT: "OFF",
|
|
4995
4976
|
EXIT_TICKET: "OFF"
|
|
4996
4977
|
});
|
|
@@ -5051,10 +5032,10 @@ var approvalPayloadSchema = zod.z.object({
|
|
|
5051
5032
|
feedback: zod.z.string().optional().describe("Actionable feedback or required changes if rejected"),
|
|
5052
5033
|
timestamp: zod.z.string().optional().describe("ISO timestamp of the approval action")
|
|
5053
5034
|
});
|
|
5054
|
-
var
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
}
|
|
5035
|
+
var lessonApprovalHook = workflow.defineHook();
|
|
5036
|
+
function approvalHookToken(projectId, lessonId, artifactType) {
|
|
5037
|
+
return `approval:${projectId}:${lessonId}:${artifactType}`;
|
|
5038
|
+
}
|
|
5058
5039
|
var BloomHintSchema = zod.z.object({
|
|
5059
5040
|
process: zod.z.enum(["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"]).describe("Cognitive process axis"),
|
|
5060
5041
|
knowledge: zod.z.enum(["FACTUAL", "CONCEPTUAL", "PROCEDURAL", "METACOGNITIVE"]).optional().describe("Knowledge dimension axis (optional \u2014 most source standards do not tag it)")
|
|
@@ -5657,9 +5638,9 @@ async function generateMilestoneWorkflow(input) {
|
|
|
5657
5638
|
} else if (lessonGate === "HITL") {
|
|
5658
5639
|
const hookToken = "gate:lesson:" + milestoneId;
|
|
5659
5640
|
console.log(" \u23F8 [Gate] LESSON awaiting HUMAN review (HITL) \u2014 hook " + hookToken);
|
|
5660
|
-
const
|
|
5661
|
-
const
|
|
5662
|
-
const hook =
|
|
5641
|
+
const workflowPkg = await import('workflow');
|
|
5642
|
+
const createHook = workflowPkg.createHook;
|
|
5643
|
+
const hook = createHook({ token: hookToken });
|
|
5663
5644
|
const review = await hook;
|
|
5664
5645
|
console.log(" \u2705 [Gate] Human verdict: " + (review.approved ? "APPROVED" : "REJECTED") + (review.feedback ? " \u2014 " + review.feedback : ""));
|
|
5665
5646
|
if (!review.approved) {
|
|
@@ -5679,7 +5660,7 @@ async function generateMilestoneWorkflow(input) {
|
|
|
5679
5660
|
standardsContext: standardsContext || void 0,
|
|
5680
5661
|
modelOptions: input.modelOptions
|
|
5681
5662
|
});
|
|
5682
|
-
const hook2 =
|
|
5663
|
+
const hook2 = createHook({ token: hookToken + ":v2" });
|
|
5683
5664
|
const review2 = await hook2;
|
|
5684
5665
|
console.log(" \u2705 [Gate] Human verdict (v2): " + (review2.approved ? "APPROVED" : "REJECTED"));
|
|
5685
5666
|
if (!review2.approved) {
|
|
@@ -5867,7 +5848,7 @@ async function generateRoadmapWorkflow(input) {
|
|
|
5867
5848
|
}
|
|
5868
5849
|
}
|
|
5869
5850
|
if (i + batchSize < milestones.length) {
|
|
5870
|
-
await
|
|
5851
|
+
await workflow.sleep("2s");
|
|
5871
5852
|
}
|
|
5872
5853
|
}
|
|
5873
5854
|
const successfulMilestones = milestoneOutcomes.filter((m) => m.status === "FULFILLED").length;
|
|
@@ -5915,6 +5896,271 @@ init_streamRunner();
|
|
|
5915
5896
|
|
|
5916
5897
|
// src/services/lessonProductionService.ts
|
|
5917
5898
|
init_streamRunner();
|
|
5899
|
+
|
|
5900
|
+
// src/ai/llmJudgeEngine.ts
|
|
5901
|
+
var LLMJudgeEngine = class {
|
|
5902
|
+
/**
|
|
5903
|
+
* Executes genuine LLM-as-Judge evaluation using the audit flow.
|
|
5904
|
+
*/
|
|
5905
|
+
static async evaluateArtifactWithLLM(input) {
|
|
5906
|
+
try {
|
|
5907
|
+
const report = await auditCurriculumQualityFlow({
|
|
5908
|
+
targetArtifactType: input.targetArtifactType,
|
|
5909
|
+
lessonId: input.lessonId,
|
|
5910
|
+
expectedLanguage: input.expectedLanguage,
|
|
5911
|
+
targetObjectives: input.targetObjectives,
|
|
5912
|
+
generatedContentJson: input.generatedContentJson,
|
|
5913
|
+
standardStatements: input.standardStatements,
|
|
5914
|
+
modelOptions: input.modelOptions
|
|
5915
|
+
});
|
|
5916
|
+
const passed = report.overallVerdict === "PASS" && report.languageAdherencePassed;
|
|
5917
|
+
const failedCriteria = report.criteria.filter((c) => !c.passed);
|
|
5918
|
+
const passedCriteria = report.criteria.filter((c) => c.passed);
|
|
5919
|
+
return {
|
|
5920
|
+
decision: report.overallVerdict === "PASS" ? "APPROVED" : report.overallVerdict === "NEEDS_REVISION" ? "NEEDS_REVISION" : "REJECTED",
|
|
5921
|
+
score: report.totalScore,
|
|
5922
|
+
passed,
|
|
5923
|
+
evaluatedBy: "@agent-as-judge",
|
|
5924
|
+
critique: passed ? `H\u1ECDc li\u1EC7u ${input.targetArtifactType} cho b\xE0i "${input.lessonId}" \u0111\u1EA1t \u0111i\u1EC3m th\u1EA9m \u0111\u1ECBnh ${report.totalScore}/100. \u0110\u1EE7 \u0111i\u1EC1u ki\u1EC7n ph\xEA duy\u1EC7t.` : `H\u1ECDc li\u1EC7u ${input.targetArtifactType} ch\u01B0a \u0111\u1EA1t y\xEAu c\u1EA7u: ${failedCriteria.map((c) => c.feedback).join("; ")}`,
|
|
5925
|
+
strengths: passedCriteria.map((c) => `${c.name}: ${c.feedback}`),
|
|
5926
|
+
weaknesses: failedCriteria.map((c) => `${c.name}: ${c.feedback}`),
|
|
5927
|
+
autoRepairInstructions: report.actionableRepairPrompts.length > 0 ? report.actionableRepairPrompts.join("\n") : void 0
|
|
5928
|
+
};
|
|
5929
|
+
} catch (err) {
|
|
5930
|
+
return {
|
|
5931
|
+
decision: "NEEDS_REVISION",
|
|
5932
|
+
score: 50,
|
|
5933
|
+
passed: false,
|
|
5934
|
+
evaluatedBy: "@agent-as-judge",
|
|
5935
|
+
critique: `L\u1ED7i trong qu\xE1 tr\xECnh th\u1EA9m \u0111\u1ECBnh LLM: ${err.message || String(err)}`,
|
|
5936
|
+
strengths: [],
|
|
5937
|
+
weaknesses: ["Kh\xF4ng th\u1EC3 ho\xE0n t\u1EA5t th\u1EA9m \u0111\u1ECBnh t\u1EF1 \u0111\u1ED9ng do s\u1EF1 c\u1ED1 k\u1EBFt n\u1ED1i m\xF4 h\xECnh."],
|
|
5938
|
+
autoRepairInstructions: "Ch\u1EA1y l\u1EA1i quy tr\xECnh th\u1EA9m \u0111\u1ECBnh ho\u1EB7c ki\u1EC3m tra c\u1EA5u h\xECnh API keys."
|
|
5939
|
+
};
|
|
5940
|
+
}
|
|
5941
|
+
}
|
|
5942
|
+
/**
|
|
5943
|
+
* Evaluates Gate 1 (SOT Foundation: LEARNER_PROFILE, PROJECT_BRIEF, REFERENCE_PACK)
|
|
5944
|
+
* Calibrated heuristic pre-check.
|
|
5945
|
+
*/
|
|
5946
|
+
static evaluateGate1(learnerProfileMarkdown, referencePackMarkdown) {
|
|
5947
|
+
if (!learnerProfileMarkdown?.trim() || !referencePackMarkdown?.trim()) {
|
|
5948
|
+
return {
|
|
5949
|
+
decision: "REJECTED",
|
|
5950
|
+
score: 0,
|
|
5951
|
+
passed: false,
|
|
5952
|
+
evaluatedBy: "@heuristic-linter",
|
|
5953
|
+
critique: "T\u1EC7p SOT r\u1ED7ng ho\u1EB7c kh\xF4ng t\u1ED3n t\u1EA1i.",
|
|
5954
|
+
strengths: [],
|
|
5955
|
+
weaknesses: ["Thi\u1EBFu n\u1ED9i dung t\u1EC7p SOT c\u01A1 s\u1EDF."],
|
|
5956
|
+
autoRepairInstructions: "Kh\u1EDFi t\u1EA1o v\xE0 bi\xEAn so\u1EA1n \u0111\u1EA7y \u0111\u1EE7 LEARNER_PROFILE.md v\xE0 REFERENCE_PACK.md."
|
|
5957
|
+
};
|
|
5958
|
+
}
|
|
5959
|
+
const hasAgeGroup = /(?:độ tuổi|lứa tuổi|age|grade|thcs|tiểu học|k-12|sinh viên|người đi làm)/i.test(learnerProfileMarkdown);
|
|
5960
|
+
const hasPriorKnowledge = /(?:kiến thức nền|nền tảng|prior knowledge|tiên quyết|prerequisite)/i.test(learnerProfileMarkdown);
|
|
5961
|
+
const hasGroundTruth = /(?:reference|csta|apple|ieee|cs2023|nguồn tham khảo|tài liệu chuẩn|rfc|w3c)/i.test(referencePackMarkdown);
|
|
5962
|
+
const hasClientObjectives = /(?:client objectives|mục tiêu|output|chuẩn đầu ra)/i.test(learnerProfileMarkdown);
|
|
5963
|
+
let score = 30;
|
|
5964
|
+
const strengths = [];
|
|
5965
|
+
const weaknesses = [];
|
|
5966
|
+
if (hasAgeGroup) {
|
|
5967
|
+
score += 20;
|
|
5968
|
+
strengths.push("H\u1ED3 s\u01A1 ng\u01B0\u1EDDi h\u1ECDc x\xE1c \u0111\u1ECBnh r\xF5 \u0111\u1ED1i t\u01B0\u1EE3ng v\xE0 l\u1EE9a tu\u1ED5i m\u1EE5c ti\xEAu.");
|
|
5969
|
+
} else {
|
|
5970
|
+
weaknesses.push("Thi\u1EBFu \u0111\u1ECBnh ngh\u0129a r\xF5 r\xE0ng v\u1EC1 \u0111\u1ED1i t\u01B0\u1EE3ng/\u0111\u1ED9 tu\u1ED5i h\u1ECDc vi\xEAn.");
|
|
5971
|
+
}
|
|
5972
|
+
if (hasPriorKnowledge) {
|
|
5973
|
+
score += 20;
|
|
5974
|
+
strengths.push("C\xF3 ph\xE2n t\xEDch ki\u1EBFn th\u1EE9c n\u1EC1n t\u1EA3ng v\xE0 r\xE0o c\u1EA3n nh\u1EADn th\u1EE9c.");
|
|
5975
|
+
} else {
|
|
5976
|
+
weaknesses.push("Ch\u01B0a l\xE0m r\xF5 ki\u1EBFn th\u1EE9c ti\xEAn quy\u1EBFt (Prerequisites).");
|
|
5977
|
+
}
|
|
5978
|
+
if (hasGroundTruth) {
|
|
5979
|
+
score += 20;
|
|
5980
|
+
strengths.push("REFERENCE_PACK tr\xEDch d\u1EABn t\xE0i li\u1EC7u k\u1EF9 thu\u1EADt chu\u1EA9n m\u1EF1c.");
|
|
5981
|
+
} else {
|
|
5982
|
+
weaknesses.push("T\u1EC7p REFERENCE_PACK thi\u1EBFu danh m\u1EE5c t\xE0i li\u1EC7u tham chi\u1EBFu chu\u1EA9n.");
|
|
5983
|
+
}
|
|
5984
|
+
if (hasClientObjectives) {
|
|
5985
|
+
score += 10;
|
|
5986
|
+
strengths.push("C\xF3 x\xE1c \u0111\u1ECBnh r\xF5 m\u1EE5c ti\xEAu \u0111\u1EA7u ra v\xE0 k\u1EF3 v\u1ECDng kh\xE1ch h\xE0ng.");
|
|
5987
|
+
}
|
|
5988
|
+
const passed = score >= 80;
|
|
5989
|
+
return {
|
|
5990
|
+
decision: passed ? "APPROVED" : score >= 60 ? "NEEDS_REVISION" : "REJECTED",
|
|
5991
|
+
score,
|
|
5992
|
+
passed,
|
|
5993
|
+
evaluatedBy: "@heuristic-linter",
|
|
5994
|
+
critique: passed ? "B\u1ED9 t\xE0i li\u1EC7u n\u1EC1n t\u1EA3ng SOT \u0111\u1EA1t chu\u1EA9n c\u1EA5u tr\xFAc. Cho ph\xE9p chuy\u1EC3n sang Phase 2 (Thi\u1EBFt k\u1EBF Khung ch\u01B0\u01A1ng tr\xECnh)." : "T\xE0i li\u1EC7u SOT c\u1EA7n b\u1ED5 sung th\xEAm c\xE1c tr\u01B0\u1EDDng th\xF4ng tin chu\u1EA9n tr\u01B0\u1EDBc khi ph\xE2n r\xE3 b\xE0i h\u1ECDc.",
|
|
5995
|
+
strengths,
|
|
5996
|
+
weaknesses,
|
|
5997
|
+
autoRepairInstructions: passed ? void 0 : "B\u1ED5 sung \u0111\u1EA7y \u0111\u1EE7 th\xF4ng tin l\u1EE9a tu\u1ED5i, ki\u1EBFn th\u1EE9c ti\xEAn quy\u1EBFt v\xE0 \xEDt nh\u1EA5t 2 ngu\u1ED3n t\xE0i li\u1EC7u k\u1EF9 thu\u1EADt chu\u1EA9n v\xE0o REFERENCE_PACK.md."
|
|
5998
|
+
};
|
|
5999
|
+
}
|
|
6000
|
+
/**
|
|
6001
|
+
* Evaluates Gate 2 (Curriculum Framework: Units, Modules, Lessons, Bloom Progression)
|
|
6002
|
+
*/
|
|
6003
|
+
static evaluateGate2(frameworkMarkdown, targetUnitCount = 4) {
|
|
6004
|
+
if (!frameworkMarkdown?.trim()) {
|
|
6005
|
+
return {
|
|
6006
|
+
decision: "REJECTED",
|
|
6007
|
+
score: 0,
|
|
6008
|
+
passed: false,
|
|
6009
|
+
evaluatedBy: "@heuristic-linter",
|
|
6010
|
+
critique: "T\u1EC7p CURRICULUM_FRAMEWORK.md r\u1ED7ng.",
|
|
6011
|
+
strengths: [],
|
|
6012
|
+
weaknesses: ["Thi\u1EBFu n\u1ED9i dung khung ch\u01B0\u01A1ng tr\xECnh."]
|
|
6013
|
+
};
|
|
6014
|
+
}
|
|
6015
|
+
const unitMatches = frameworkMarkdown.match(/(?:##\s+(?:Unit\s+\d+|U\d{2})|\|\s*U\d{2}\s*:|\|\s*Unit\s+\d+)/gi) || [];
|
|
6016
|
+
const hasBloom = /(?:bloom|nhận biết|thông hiểu|vận dụng|phân tích|đánh giá|sáng tạo|remember|understand|apply|analyze|evaluate|create)/i.test(frameworkMarkdown);
|
|
6017
|
+
const has5E = /(?:5e|engage|explore|explain|elaborate|evaluate|pbl|edp|hybrid)/i.test(frameworkMarkdown);
|
|
6018
|
+
const hasScopeSequence = /(?:scope & sequence|lộ trình|tiến trình|bài học)/i.test(frameworkMarkdown);
|
|
6019
|
+
let score = 30;
|
|
6020
|
+
const strengths = [];
|
|
6021
|
+
const weaknesses = [];
|
|
6022
|
+
if (unitMatches.length >= targetUnitCount) {
|
|
6023
|
+
score += 25;
|
|
6024
|
+
strengths.push(`Ph\xE2n r\xE3 \u0111\u1EE7 ${unitMatches.length} Units theo \u0111\xFAng y\xEAu c\u1EA7u c\u1EA5u tr\xFAc.`);
|
|
6025
|
+
} else {
|
|
6026
|
+
score += Math.min(20, unitMatches.length * 5);
|
|
6027
|
+
weaknesses.push(`S\u1ED1 l\u01B0\u1EE3ng Unit (${unitMatches.length}) ch\u01B0a \u0111\u1EA1t m\u1EE5c ti\xEAu ${targetUnitCount} Units.`);
|
|
6028
|
+
}
|
|
6029
|
+
if (hasBloom) {
|
|
6030
|
+
score += 20;
|
|
6031
|
+
strengths.push("C\xF3 ph\xE2n b\u1ED5 thang \u0111o Bloom r\xF5 r\xE0ng theo ti\u1EBFn tr\xECnh nh\u1EADn th\u1EE9c.");
|
|
6032
|
+
} else {
|
|
6033
|
+
weaknesses.push("Thi\u1EBFu \xE1nh x\u1EA1 m\u1EE9c \u0111\u1ED9 Bloom trong c\xE1c b\xE0i h\u1ECDc.");
|
|
6034
|
+
}
|
|
6035
|
+
if (has5E) {
|
|
6036
|
+
score += 15;
|
|
6037
|
+
strengths.push("C\u1EA5u tr\xFAc b\xE0i h\u1ECDc \u0111\u1ECBnh h\u01B0\u1EDBng chu\u1EA9n m\xF4 h\xECnh s\u01B0 ph\u1EA1m (5E/PBL/EDP).");
|
|
6038
|
+
}
|
|
6039
|
+
if (hasScopeSequence) {
|
|
6040
|
+
score += 10;
|
|
6041
|
+
strengths.push("C\xF3 b\u1EA3ng Scope & Sequence chi ti\u1EBFt.");
|
|
6042
|
+
}
|
|
6043
|
+
const passed = score >= 80;
|
|
6044
|
+
return {
|
|
6045
|
+
decision: passed ? "APPROVED" : score >= 60 ? "NEEDS_REVISION" : "REJECTED",
|
|
6046
|
+
score,
|
|
6047
|
+
passed,
|
|
6048
|
+
evaluatedBy: "@heuristic-linter",
|
|
6049
|
+
critique: passed ? "Khung ch\u01B0\u01A1ng tr\xECnh \u0111\u1EA1t chu\u1EA9n ki\u1EBFn tr\xFAc ph\xE2n r\xE3. Cho ph\xE9p ti\u1EBFn h\xE0nh s\u1EA3n xu\u1EA5t h\u1ECDc li\u1EC7u." : "C\u1EA7n b\u1ED5 sung chi ti\u1EBFt c\u1EA5u tr\xFAc b\xE0i h\u1ECDc, b\u1EA3ng ph\xE2n r\xE3 v\xE0 m\u1EE9c \u0111\u1ED9 Bloom t\u01B0\u01A1ng \u1EE9ng.",
|
|
6050
|
+
strengths,
|
|
6051
|
+
weaknesses
|
|
6052
|
+
};
|
|
6053
|
+
}
|
|
6054
|
+
/**
|
|
6055
|
+
* Evaluates a produced Lesson Artifact (LESSON, ACT, QUIZ, SLIDE) with heuristic structure checks
|
|
6056
|
+
*/
|
|
6057
|
+
static evaluateArtifact(artifactType, content, lessonTitle) {
|
|
6058
|
+
if (!content?.trim() || content.trim().length < 50) {
|
|
6059
|
+
return {
|
|
6060
|
+
decision: "REJECTED",
|
|
6061
|
+
score: 0,
|
|
6062
|
+
passed: false,
|
|
6063
|
+
evaluatedBy: "@heuristic-linter",
|
|
6064
|
+
critique: `N\u1ED9i dung ${artifactType} cho b\xE0i "${lessonTitle}" qu\xE1 ng\u1EAFn ho\u1EB7c r\u1ED7ng.`,
|
|
6065
|
+
strengths: [],
|
|
6066
|
+
weaknesses: ["H\u1ECDc li\u1EC7u kh\xF4ng c\xF3 n\u1ED9i dung th\u1EF1c t\u1EBF."]
|
|
6067
|
+
};
|
|
6068
|
+
}
|
|
6069
|
+
let score = 40;
|
|
6070
|
+
const strengths = [];
|
|
6071
|
+
const weaknesses = [];
|
|
6072
|
+
switch (artifactType.toUpperCase()) {
|
|
6073
|
+
case "LESSON": {
|
|
6074
|
+
const phases = [
|
|
6075
|
+
{ name: "Engage", regex: /(?:Engage|Khởi động|Warm-up|Hook|Mở đầu)/i },
|
|
6076
|
+
{ name: "Explore", regex: /(?:Explore|Khám phá|Demo|Thử nghiệm)/i },
|
|
6077
|
+
{ name: "Explain", regex: /(?:Explain|Giải thích|Core Concepts|Lý thuyết)/i },
|
|
6078
|
+
{ name: "Elaborate", regex: /(?:Elaborate|Vận dụng|Guided Practice|Independent Practice|Challenge|Thực hành)/i },
|
|
6079
|
+
{ name: "Evaluate", regex: /(?:Evaluate|Đánh giá|Wrap-up|Exit Ticket|Tổng kết)/i }
|
|
6080
|
+
];
|
|
6081
|
+
let phaseCount = 0;
|
|
6082
|
+
for (const p of phases) {
|
|
6083
|
+
if (p.regex.test(content)) phaseCount++;
|
|
6084
|
+
}
|
|
6085
|
+
score += phaseCount * 10;
|
|
6086
|
+
if (phaseCount >= 4) {
|
|
6087
|
+
strengths.push(`Gi\xE1o \xE1n bao ph\u1EE7 ${phaseCount}/5 pha c\u1EE7a ti\u1EBFn tr\xECnh 5E.`);
|
|
6088
|
+
} else {
|
|
6089
|
+
weaknesses.push(`Gi\xE1o \xE1n ch\u1EC9 c\xF3 ${phaseCount}/5 pha 5E.`);
|
|
6090
|
+
}
|
|
6091
|
+
if (content.length > 500) score += 10;
|
|
6092
|
+
break;
|
|
6093
|
+
}
|
|
6094
|
+
case "ACT": {
|
|
6095
|
+
const hasSteps = /(?:bước|step\s+\d+|hướng dẫn)/i.test(content);
|
|
6096
|
+
const hasCode = /```[\s\S]*?```/.test(content);
|
|
6097
|
+
const hasObjectives = /(?:mục tiêu|objective|yêu cầu)/i.test(content);
|
|
6098
|
+
if (hasSteps) {
|
|
6099
|
+
score += 20;
|
|
6100
|
+
strengths.push("B\xE0i th\u1EF1c h\xE0nh c\xF3 quy tr\xECnh t\u1EEBng b\u01B0\u1EDBc r\xF5 r\xE0ng.");
|
|
6101
|
+
}
|
|
6102
|
+
if (hasCode) {
|
|
6103
|
+
score += 20;
|
|
6104
|
+
strengths.push("C\xF3 m\xE3 ngu\u1ED3n m\u1EABu/l\u1EC7nh th\u1EF1c thi minh h\u1ECDa.");
|
|
6105
|
+
}
|
|
6106
|
+
if (hasObjectives) {
|
|
6107
|
+
score += 10;
|
|
6108
|
+
strengths.push("C\xF3 x\xE1c \u0111\u1ECBnh m\u1EE5c ti\xEAu th\u1EF1c h\xE0nh.");
|
|
6109
|
+
}
|
|
6110
|
+
break;
|
|
6111
|
+
}
|
|
6112
|
+
case "QUIZ": {
|
|
6113
|
+
const hasQuestions = /(?:question\s*\d+|câu\s*\d+|\?)/i.test(content);
|
|
6114
|
+
const hasOptions = /(?:[A-D]\.|\"options\")/i.test(content);
|
|
6115
|
+
const hasExplanation = /(?:explanation|giải thích|vì sao|đáp án)/i.test(content);
|
|
6116
|
+
if (hasQuestions) {
|
|
6117
|
+
score += 20;
|
|
6118
|
+
strengths.push("C\xF3 c\xE2u h\u1ECFi ch\u1EA9n \u0111o\xE1n.");
|
|
6119
|
+
}
|
|
6120
|
+
if (hasOptions) {
|
|
6121
|
+
score += 20;
|
|
6122
|
+
strengths.push("\u0110\u1EA7y \u0111\u1EE7 c\xE1c l\u1EF1a ch\u1ECDn \u0111\xE1p \xE1n.");
|
|
6123
|
+
}
|
|
6124
|
+
if (hasExplanation) {
|
|
6125
|
+
score += 15;
|
|
6126
|
+
strengths.push("C\xF3 ph\u1EA7n gi\u1EA3i th\xEDch \u0111\xE1p \xE1n chi ti\u1EBFt.");
|
|
6127
|
+
}
|
|
6128
|
+
break;
|
|
6129
|
+
}
|
|
6130
|
+
case "SLIDE": {
|
|
6131
|
+
const hasMarp = /(?:marp:\s*true|---\s*\n)/i.test(content);
|
|
6132
|
+
const slideCount = (content.match(/---\s*\n/g) || []).length;
|
|
6133
|
+
if (hasMarp) {
|
|
6134
|
+
score += 25;
|
|
6135
|
+
strengths.push("\u0110\u1ECBnh d\u1EA1ng t\u01B0\u01A1ng th\xEDch Marp Presentation.");
|
|
6136
|
+
}
|
|
6137
|
+
if (slideCount >= 5) {
|
|
6138
|
+
score += 25;
|
|
6139
|
+
strengths.push(`B\u1ED9 slide c\xF3 dung l\u01B0\u1EE3ng h\u1EE3p l\xFD (${slideCount + 1} slides).`);
|
|
6140
|
+
} else {
|
|
6141
|
+
weaknesses.push(`S\u1ED1 l\u01B0\u1EE3ng slide (${slideCount + 1}) c\xF2n qu\xE1 \xEDt.`);
|
|
6142
|
+
}
|
|
6143
|
+
break;
|
|
6144
|
+
}
|
|
6145
|
+
default: {
|
|
6146
|
+
if (content.length > 200) score += 40;
|
|
6147
|
+
break;
|
|
6148
|
+
}
|
|
6149
|
+
}
|
|
6150
|
+
const passed = score >= 80;
|
|
6151
|
+
return {
|
|
6152
|
+
decision: passed ? "APPROVED" : score >= 60 ? "NEEDS_REVISION" : "REJECTED",
|
|
6153
|
+
score: Math.min(100, score),
|
|
6154
|
+
passed,
|
|
6155
|
+
evaluatedBy: "@heuristic-linter",
|
|
6156
|
+
critique: passed ? `H\u1ECDc li\u1EC7u ${artifactType} cho b\xE0i "${lessonTitle}" \u0111\u1EA1t ki\u1EC3m tra c\u1EA5u tr\xFAc (${score}/100).` : `H\u1ECDc li\u1EC7u ${artifactType} c\u1EA7n ho\xE0n thi\u1EC7n th\xEAm c\u1EA5u tr\xFAc \u0111\u1EC3 \u0111\u1EA1t chu\u1EA9n s\u01B0 ph\u1EA1m (${score}/100).`,
|
|
6157
|
+
strengths,
|
|
6158
|
+
weaknesses
|
|
6159
|
+
};
|
|
6160
|
+
}
|
|
6161
|
+
};
|
|
6162
|
+
|
|
6163
|
+
// src/services/lessonProductionService.ts
|
|
5918
6164
|
init_errors();
|
|
5919
6165
|
|
|
5920
6166
|
// src/services/lessonProductionService.ts
|
|
@@ -6014,6 +6260,8 @@ async function generateSingleArtifact(req) {
|
|
|
6014
6260
|
extraContext,
|
|
6015
6261
|
config,
|
|
6016
6262
|
contextSot = {},
|
|
6263
|
+
mediaPolicy,
|
|
6264
|
+
researchContext,
|
|
6017
6265
|
options = {},
|
|
6018
6266
|
onChunk
|
|
6019
6267
|
} = req;
|
|
@@ -6051,7 +6299,10 @@ ${langRule}
|
|
|
6051
6299
|
3. PEDAGOGICAL GROUNDING: Strictly align with the ${pedagogy.toUpperCase()} model, Bloom's Revised Taxonomy, and IEEE/ACM CS2023 guidelines.
|
|
6052
6300
|
4. SCAFFOLDING LEVEL: "${scaffoldingLevel.toUpperCase()}".${scaffoldingRule}
|
|
6053
6301
|
5. TARGET AUDIENCE: ${gradeLevel ? `Grade ${gradeLevel}, ` : ""}${targetAge} on ${hwStr}.${deviceRule}${classDynamicsRule}${extraContextRule}
|
|
6054
|
-
6. OUTPUT INTEGRITY: Output clean Markdown starting directly with YAML frontmatter. Do not wrap entire response in triple backticks.${artifactSpecializedPrompt}
|
|
6302
|
+
6. OUTPUT INTEGRITY: Output clean Markdown starting directly with YAML frontmatter. Do not wrap entire response in triple backticks.${artifactSpecializedPrompt}${mediaPolicy ? `
|
|
6303
|
+
|
|
6304
|
+
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).
|
|
6305
|
+
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.` : ""}`;
|
|
6055
6306
|
const userPrompt = `### CONTEXT GROUND TRUTH:
|
|
6056
6307
|
- Topic / Concept Domain: "${topic}"
|
|
6057
6308
|
- Lesson ID: "${lessonId || "ON_DEMAND"}"
|
|
@@ -6066,6 +6317,9 @@ ${selectedDevices ? `- Device Mode: "${selectedDevices}"
|
|
|
6066
6317
|
` : ""}${extraContext ? `- User Specific Guidance & Requirements: "${extraContext}"
|
|
6067
6318
|
` : ""}${config ? `- Full Task Config: ${JSON.stringify(config)}
|
|
6068
6319
|
` : ""}
|
|
6320
|
+
${researchContext ? `### RESEARCH GROUND TRUTH (fact-checked context \u2014 \u01B0u ti\xEAn d\xF9ng, KH\xD4NG b\u1ECBa s\u1ED1 li\u1EC7u):
|
|
6321
|
+
${researchContext.slice(0, 4e3)}
|
|
6322
|
+
` : ""}
|
|
6069
6323
|
${contextSot.framework ? `### SOT CURRICULUM FRAMEWORK:
|
|
6070
6324
|
${contextSot.framework.slice(0, 1500)}
|
|
6071
6325
|
` : ""}
|
|
@@ -6106,13 +6360,171 @@ Generate the complete, thorough, publication-grade "${artifactType.toUpperCase()
|
|
|
6106
6360
|
}
|
|
6107
6361
|
);
|
|
6108
6362
|
const { thought, content } = extractThoughtAndContent(rawResult);
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6363
|
+
const finalContent = content || accumulatedContent;
|
|
6364
|
+
const finalThought = thought || accumulatedThought;
|
|
6365
|
+
const gates = resolveGateSettings(req.gateSettings);
|
|
6366
|
+
const kitGateType = {
|
|
6367
|
+
lesson: "LESSON",
|
|
6368
|
+
slide: "SLIDE",
|
|
6369
|
+
act: "ACT",
|
|
6370
|
+
quiz: "QUIZ",
|
|
6371
|
+
guide: "GUIDE",
|
|
6372
|
+
handout: "HANDOUT",
|
|
6373
|
+
worksheet: "WKS",
|
|
6374
|
+
ext: "EXT",
|
|
6375
|
+
codelab: "CODE",
|
|
6376
|
+
exit_ticket: "EXIT_TICKET"
|
|
6377
|
+
}[artifactType];
|
|
6378
|
+
const gateMode = kitGateType ? gateModeFor(gates, kitGateType) : "OFF";
|
|
6379
|
+
if (gateMode === "OFF") {
|
|
6380
|
+
return { artifactType, filename: meta.filename, content: finalContent, persona: meta.persona, thought: finalThought };
|
|
6381
|
+
}
|
|
6382
|
+
const injectReviewMeta = (doc, metaMap) => {
|
|
6383
|
+
const fm = doc.match(/^---\s*\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
6384
|
+
if (!fm) {
|
|
6385
|
+
return `---
|
|
6386
|
+
${Object.entries(metaMap).map(([k, v]) => `${k}: "${v}"`).join("\n")}
|
|
6387
|
+
---
|
|
6388
|
+
|
|
6389
|
+
${doc}`;
|
|
6390
|
+
}
|
|
6391
|
+
let yaml = fm[1] ?? "";
|
|
6392
|
+
for (const [k, v] of Object.entries(metaMap)) {
|
|
6393
|
+
const re = new RegExp(`^${k}:.*$`, "m");
|
|
6394
|
+
if (re.test(yaml)) yaml = yaml.replace(re, `${k}: "${v}"`);
|
|
6395
|
+
else yaml += `
|
|
6396
|
+
${k}: "${v}"`;
|
|
6397
|
+
}
|
|
6398
|
+
return doc.replace(fm[0], `---
|
|
6399
|
+
${yaml.trim()}
|
|
6400
|
+
---
|
|
6401
|
+
`);
|
|
6115
6402
|
};
|
|
6403
|
+
if (gateMode === "HITL") {
|
|
6404
|
+
return {
|
|
6405
|
+
artifactType,
|
|
6406
|
+
filename: meta.filename,
|
|
6407
|
+
content: injectReviewMeta(finalContent, { review_status: "PENDING_REVIEW", review_decision: "PENDING" }),
|
|
6408
|
+
persona: meta.persona,
|
|
6409
|
+
thought: finalThought,
|
|
6410
|
+
pausedForReview: true,
|
|
6411
|
+
gateStatus: "awaiting_approval"
|
|
6412
|
+
};
|
|
6413
|
+
}
|
|
6414
|
+
const judgeObjectives = [{ code: "A1", description: `Artifact fulfills its pedagogical contract for topic "${topic}" with complete required sections`, bloomLevel: "Analyze" }];
|
|
6415
|
+
try {
|
|
6416
|
+
const verdict = await LLMJudgeEngine.evaluateArtifactWithLLM({
|
|
6417
|
+
targetArtifactType: artifactType.toUpperCase(),
|
|
6418
|
+
lessonId: lessonId || "ON_DEMAND",
|
|
6419
|
+
expectedLanguage: language.toLowerCase().includes("viet") ? "vietnamese" : "english",
|
|
6420
|
+
targetObjectives: judgeObjectives,
|
|
6421
|
+
generatedContentJson: JSON.stringify({ content: finalContent, artifactType, lessonId: lessonId || "ON_DEMAND", title: displayTitle })
|
|
6422
|
+
});
|
|
6423
|
+
const passed = Boolean(verdict.passed) && verdict.score >= 85;
|
|
6424
|
+
if (passed) {
|
|
6425
|
+
return {
|
|
6426
|
+
artifactType,
|
|
6427
|
+
filename: meta.filename,
|
|
6428
|
+
content: injectReviewMeta(finalContent, {
|
|
6429
|
+
review_status: "APPROVED",
|
|
6430
|
+
reviewed_by: "@reviewer (LLM-as-Judge)",
|
|
6431
|
+
review_decision: "APPROVED"
|
|
6432
|
+
}),
|
|
6433
|
+
persona: meta.persona,
|
|
6434
|
+
thought: finalThought,
|
|
6435
|
+
judgeScore: verdict.score,
|
|
6436
|
+
judgeCritique: verdict.critique
|
|
6437
|
+
};
|
|
6438
|
+
}
|
|
6439
|
+
const repairFeedback = [verdict.autoRepairInstructions, ...verdict.weaknesses || []].filter(Boolean).join("\n");
|
|
6440
|
+
const repairedRaw = await streamCurriculumAIInference(
|
|
6441
|
+
[
|
|
6442
|
+
{ role: "user", content: `You previously authored \`${meta.filename}\` and the academic Judge REJECTED it with the critique below.
|
|
6443
|
+
Rewrite the COMPLETE corrected document: fix every listed issue, keep the mandatory structure, frontmatter and all approved sections. Output 100% clean Markdown only.
|
|
6444
|
+
|
|
6445
|
+
JUDGE CRITIQUE:
|
|
6446
|
+
${repairFeedback}
|
|
6447
|
+
|
|
6448
|
+
CURRENT DOCUMENT:
|
|
6449
|
+
${finalContent}` }
|
|
6450
|
+
],
|
|
6451
|
+
userPrompt,
|
|
6452
|
+
{ ...options, systemPersona: systemPrompt },
|
|
6453
|
+
(chunk, type) => {
|
|
6454
|
+
if (onChunk) onChunk(chunk, type === "thought" ? "thought" : "content");
|
|
6455
|
+
}
|
|
6456
|
+
);
|
|
6457
|
+
const repairedExtract = extractThoughtAndContent(repairedRaw);
|
|
6458
|
+
const repaired = repairedExtract.content || repairedRaw;
|
|
6459
|
+
if (repaired && repaired.trim().length > 100) {
|
|
6460
|
+
const reVerdict = await LLMJudgeEngine.evaluateArtifactWithLLM({
|
|
6461
|
+
targetArtifactType: artifactType.toUpperCase(),
|
|
6462
|
+
lessonId: lessonId || "ON_DEMAND",
|
|
6463
|
+
expectedLanguage: language.toLowerCase().includes("viet") ? "vietnamese" : "english",
|
|
6464
|
+
targetObjectives: judgeObjectives,
|
|
6465
|
+
generatedContentJson: JSON.stringify({ content: repaired, artifactType, lessonId: lessonId || "ON_DEMAND", title: displayTitle })
|
|
6466
|
+
});
|
|
6467
|
+
if (reVerdict.passed && reVerdict.score >= 85) {
|
|
6468
|
+
return {
|
|
6469
|
+
artifactType,
|
|
6470
|
+
filename: meta.filename,
|
|
6471
|
+
content: injectReviewMeta(repaired, {
|
|
6472
|
+
review_status: "APPROVED",
|
|
6473
|
+
reviewed_by: "@reviewer (LLM-as-Judge)",
|
|
6474
|
+
review_decision: "APPROVED"
|
|
6475
|
+
}),
|
|
6476
|
+
persona: meta.persona,
|
|
6477
|
+
thought: repairedExtract.thought || "",
|
|
6478
|
+
judgeScore: reVerdict.score,
|
|
6479
|
+
judgeCritique: reVerdict.critique
|
|
6480
|
+
};
|
|
6481
|
+
}
|
|
6482
|
+
return {
|
|
6483
|
+
artifactType,
|
|
6484
|
+
filename: meta.filename,
|
|
6485
|
+
content: injectReviewMeta(repaired, {
|
|
6486
|
+
review_status: "NEEDS_REVISION",
|
|
6487
|
+
reviewed_by: "@reviewer (LLM-as-Judge)",
|
|
6488
|
+
review_decision: "NEEDS_REVISION"
|
|
6489
|
+
}),
|
|
6490
|
+
persona: meta.persona,
|
|
6491
|
+
thought: repairedExtract.thought || "",
|
|
6492
|
+
pausedForReview: true,
|
|
6493
|
+
gateStatus: "judge_needs_revision",
|
|
6494
|
+
judgeScore: reVerdict.score,
|
|
6495
|
+
judgeCritique: reVerdict.critique
|
|
6496
|
+
};
|
|
6497
|
+
}
|
|
6498
|
+
return {
|
|
6499
|
+
artifactType,
|
|
6500
|
+
filename: meta.filename,
|
|
6501
|
+
content: injectReviewMeta(finalContent, {
|
|
6502
|
+
review_status: "NEEDS_REVISION",
|
|
6503
|
+
reviewed_by: "@reviewer (LLM-as-Judge)",
|
|
6504
|
+
review_decision: "NEEDS_REVISION"
|
|
6505
|
+
}),
|
|
6506
|
+
persona: meta.persona,
|
|
6507
|
+
thought: finalThought,
|
|
6508
|
+
pausedForReview: true,
|
|
6509
|
+
gateStatus: "judge_needs_revision",
|
|
6510
|
+
judgeScore: verdict.score,
|
|
6511
|
+
judgeCritique: verdict.critique
|
|
6512
|
+
};
|
|
6513
|
+
} catch (judgeErr) {
|
|
6514
|
+
return {
|
|
6515
|
+
artifactType,
|
|
6516
|
+
filename: meta.filename,
|
|
6517
|
+
content: injectReviewMeta(finalContent, {
|
|
6518
|
+
review_status: "NEEDS_REVISION",
|
|
6519
|
+
review_decision: "NEEDS_REVISION",
|
|
6520
|
+
critique: `Judge unavailable (fail-closed): ${String(judgeErr?.message || judgeErr).slice(0, 300)}`
|
|
6521
|
+
}),
|
|
6522
|
+
persona: meta.persona,
|
|
6523
|
+
thought: finalThought,
|
|
6524
|
+
pausedForReview: true,
|
|
6525
|
+
gateStatus: "judge_error"
|
|
6526
|
+
};
|
|
6527
|
+
}
|
|
6116
6528
|
} catch (error) {
|
|
6117
6529
|
throw createAiInferenceError({
|
|
6118
6530
|
errorCode: "ERR_AI_ALL_PROVIDERS_FAILED",
|
|
@@ -6387,6 +6799,7 @@ async function generateSingleArtifactWorkflow(request) {
|
|
|
6387
6799
|
}
|
|
6388
6800
|
|
|
6389
6801
|
exports.DEFAULT_GATE_SETTINGS = DEFAULT_GATE_SETTINGS;
|
|
6802
|
+
exports.approvalHookToken = approvalHookToken;
|
|
6390
6803
|
exports.approvalPayloadSchema = approvalPayloadSchema;
|
|
6391
6804
|
exports.executeSingleArtifactStep = executeSingleArtifactStep;
|
|
6392
6805
|
exports.gateModeFor = gateModeFor;
|