@thanh01.pmt/curriculum-kit 1.0.12 → 1.0.13

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 CHANGED
@@ -13525,6 +13525,78 @@ var DeterministicPipelineRunner = class {
13525
13525
 
13526
13526
  // src/services/prefillService.ts
13527
13527
  init_streamRunner();
13528
+ var DEFAULT_STREAM_IDLE_MS = 45e3;
13529
+ var DEFAULT_STREAM_TOTAL_MS = 3e5;
13530
+ var LAYER_TOTAL_BUDGET_MS = {
13531
+ 1: 18e4,
13532
+ 2: 36e4,
13533
+ 3: 36e4
13534
+ };
13535
+ function resolveStreamBudget(layer, opts) {
13536
+ const envIdle = Number(process.env.WIZARD_PREFILL_IDLE_TIMEOUT_MS);
13537
+ const envTotal = Number(process.env.WIZARD_PREFILL_TOTAL_TIMEOUT_MS);
13538
+ const layerTotal = layer !== void 0 ? LAYER_TOTAL_BUDGET_MS[layer] : void 0;
13539
+ return {
13540
+ idleMs: opts?.idleMs ?? (Number.isFinite(envIdle) && envIdle > 0 ? envIdle : DEFAULT_STREAM_IDLE_MS),
13541
+ totalMs: opts?.totalMs ?? (Number.isFinite(envTotal) && envTotal > 0 ? envTotal : layerTotal ?? DEFAULT_STREAM_TOTAL_MS)
13542
+ };
13543
+ }
13544
+ function extractStreamChunk(part) {
13545
+ if (!part || typeof part !== "object") return {};
13546
+ if (part.type === "reasoning-delta" || part.type === "reasoning") {
13547
+ const thought = part.text ?? part.delta ?? part.reasoning ?? "";
13548
+ return thought ? { thought } : {};
13549
+ }
13550
+ if (part.type === "text-delta") {
13551
+ const content = part.text ?? part.delta ?? "";
13552
+ return content ? { content } : {};
13553
+ }
13554
+ if (part.type === "raw") {
13555
+ const raw = part.rawValue;
13556
+ const delta = raw?.choices?.[0]?.delta;
13557
+ const reasoning = delta?.reasoning_content ?? delta?.reasoning ?? raw?.delta?.reasoning_content ?? raw?.delta?.reasoning;
13558
+ if (typeof reasoning === "string" && reasoning) return { thought: reasoning };
13559
+ const text = delta?.content ?? raw?.delta?.content;
13560
+ if (typeof text === "string" && text) return { content: text };
13561
+ return {};
13562
+ }
13563
+ return {};
13564
+ }
13565
+ function createStreamAbortSignal(budget) {
13566
+ const controller = new AbortController();
13567
+ let idleTimer = null;
13568
+ let totalTimer = null;
13569
+ const armIdle = () => {
13570
+ if (idleTimer) clearTimeout(idleTimer);
13571
+ if (budget.idleMs > 0) {
13572
+ idleTimer = setTimeout(
13573
+ () => controller.abort(new Error(`Idle timeout: no data for ${Math.round(budget.idleMs / 1e3)}s`)),
13574
+ budget.idleMs
13575
+ );
13576
+ idleTimer?.unref?.();
13577
+ }
13578
+ };
13579
+ armIdle();
13580
+ if (budget.totalMs > 0) {
13581
+ totalTimer = setTimeout(
13582
+ () => controller.abort(new Error(`Total stream timeout after ${Math.round(budget.totalMs / 1e3)}s`)),
13583
+ budget.totalMs
13584
+ );
13585
+ totalTimer?.unref?.();
13586
+ }
13587
+ return {
13588
+ signal: controller.signal,
13589
+ /** Reset the idle window — call on EVERY received stream part. */
13590
+ kick: armIdle,
13591
+ /** Clear both timers once the stream lifecycle is over. */
13592
+ dispose: () => {
13593
+ if (idleTimer) clearTimeout(idleTimer);
13594
+ if (totalTimer) clearTimeout(totalTimer);
13595
+ idleTimer = null;
13596
+ totalTimer = null;
13597
+ }
13598
+ };
13599
+ }
13528
13600
  function safeParseJson(rawText) {
13529
13601
  if (!rawText) return null;
13530
13602
  const cleaned = rawText.replace(/```json\s*/gi, "").replace(/```\s*/g, "").trim();
@@ -13549,7 +13621,7 @@ function safeParseJson(rawText) {
13549
13621
  return null;
13550
13622
  }
13551
13623
  }
13552
- async function streamLLMWithFallback(systemPrompt, userPrompt, apiKeys = {}, onChunk, preferredModel, preferredProvider) {
13624
+ async function streamLLMWithFallback(systemPrompt, userPrompt, apiKeys = {}, onChunk, preferredModel, preferredProvider, budget) {
13553
13625
  const alibabaKey = apiKeys.alibaba || apiKeys.dashscope || process.env.ALIBABA_API_KEY || process.env.DASHSCOPE_API_KEY;
13554
13626
  const nvidiaKey = apiKeys.nvidia || process.env.NVIDIA_API_KEY;
13555
13627
  const deepseekKey = apiKeys.deepseek || process.env.DEEPSEEK_API_KEY;
@@ -13627,8 +13699,13 @@ async function streamLLMWithFallback(systemPrompt, userPrompt, apiKeys = {}, onC
13627
13699
  const systemInstructions = `${systemPrompt}
13628
13700
 
13629
13701
  THINKING DIRECTIVE: Keep reasoning concise, structured, and focused strictly on the core pedagogical trade-offs in 4-6 concise bullet points (under 120 words). Then output the JSON immediately.`;
13702
+ const resolvedBudget = {
13703
+ idleMs: budget?.idleMs ?? DEFAULT_STREAM_IDLE_MS,
13704
+ totalMs: budget?.totalMs ?? DEFAULT_STREAM_TOTAL_MS
13705
+ };
13630
13706
  for (const candidate of candidates) {
13631
13707
  const t0 = Date.now();
13708
+ const abort = createStreamAbortSignal(resolvedBudget);
13632
13709
  try {
13633
13710
  const modelInstance = getAIModel({
13634
13711
  provider: candidate.provider,
@@ -13641,26 +13718,16 @@ THINKING DIRECTIVE: Keep reasoning concise, structured, and focused strictly on
13641
13718
  prompt: userPrompt,
13642
13719
  temperature: 0.2,
13643
13720
  includeRawChunks: true,
13644
- abortSignal: AbortSignal.timeout(6e4)
13721
+ abortSignal: abort.signal
13645
13722
  });
13646
13723
  let fullContent = "";
13647
13724
  for await (const part of streamResult.fullStream) {
13648
- if (part.type === "reasoning-delta") {
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
- }
13658
- } else if (part.type === "text-delta") {
13659
- const textDelta = part.text ?? part.delta ?? "";
13660
- if (textDelta) {
13661
- fullContent += textDelta;
13662
- onChunk?.(textDelta, "content");
13663
- }
13725
+ abort.kick();
13726
+ const extracted = extractStreamChunk(part);
13727
+ if (extracted.thought) onChunk?.(extracted.thought, "thought");
13728
+ if (extracted.content) {
13729
+ fullContent += extracted.content;
13730
+ onChunk?.(extracted.content, "content");
13664
13731
  }
13665
13732
  }
13666
13733
  if (fullContent.trim()) {
@@ -13669,6 +13736,8 @@ THINKING DIRECTIVE: Keep reasoning concise, structured, and focused strictly on
13669
13736
  }
13670
13737
  } catch (e) {
13671
13738
  console.warn(`[curriculum-kit:VercelAI] Candidate ${candidate.provider} (${candidate.model}) failed in ${Date.now() - t0}ms:`, e?.message || e);
13739
+ } finally {
13740
+ abort.dispose();
13672
13741
  }
13673
13742
  }
13674
13743
  return null;
@@ -13709,7 +13778,11 @@ Return concise JSON matching:
13709
13778
  (chunk, type) => {
13710
13779
  if (type === "content") rawContent += chunk;
13711
13780
  onChunk?.(chunk, type);
13712
- }
13781
+ },
13782
+ options.model,
13783
+ options.provider,
13784
+ // Research may run live web grounding — generous budget, still idle-guarded.
13785
+ resolveStreamBudget(void 0, { idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs })
13713
13786
  );
13714
13787
  let parsedResearch = {
13715
13788
  groundTruthSummary: `Verified ecosystem standards for ${projectName}`,
@@ -13911,7 +13984,10 @@ REQUIREMENT: Synthesize ALL parameters above \u2014 every single line in FULL AC
13911
13984
  onChunk?.(chunk, type);
13912
13985
  },
13913
13986
  options.model,
13914
- options.provider
13987
+ options.provider,
13988
+ // RC-W1: layer-aware budget — Layer 2 has the largest output and free-tier
13989
+ // models may think/stream for minutes. Idle window still catches hangs.
13990
+ resolveStreamBudget(targetLayer, { idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs })
13915
13991
  );
13916
13992
  const parsed = safeParseJson(rawContent);
13917
13993
  return {
@@ -17190,6 +17266,8 @@ exports.CurriculumPlanSchema = CurriculumPlanSchema;
17190
17266
  exports.CurriculumQualityReportSchema = CurriculumQualityReportSchema;
17191
17267
  exports.DEFAULT_ENABLED_PROVIDERS = DEFAULT_ENABLED_PROVIDERS;
17192
17268
  exports.DEFAULT_GATE_SETTINGS = DEFAULT_GATE_SETTINGS;
17269
+ exports.DEFAULT_STREAM_IDLE_MS = DEFAULT_STREAM_IDLE_MS;
17270
+ exports.DEFAULT_STREAM_TOTAL_MS = DEFAULT_STREAM_TOTAL_MS;
17193
17271
  exports.DependencyEdgeSchema = DependencyEdgeSchema;
17194
17272
  exports.DepthAssignmentSchema = DepthAssignmentSchema;
17195
17273
  exports.DepthLevelSchema = DepthLevelSchema;
@@ -17234,6 +17312,7 @@ exports.HandoutSectionSchema = HandoutSectionSchema;
17234
17312
  exports.InstructionSectionSchema = InstructionSectionSchema;
17235
17313
  exports.InstructionStepSchema = InstructionStepSchema;
17236
17314
  exports.JudgeCriterionSchema = JudgeCriterionSchema;
17315
+ exports.LAYER_TOTAL_BUDGET_MS = LAYER_TOTAL_BUDGET_MS;
17237
17316
  exports.LESSON_PLAN_TEMPLATE = LESSON_PLAN_TEMPLATE;
17238
17317
  exports.LLMJudgeEngine = LLMJudgeEngine;
17239
17318
  exports.LabTierTaskSchema = LabTierTaskSchema;
@@ -17363,6 +17442,7 @@ exports.contentTools = contentTools;
17363
17442
  exports.convertRoadmapToFoundationSot = convertRoadmapToFoundationSot;
17364
17443
  exports.createAiInferenceError = createAiInferenceError;
17365
17444
  exports.createCurriculumStorage = createCurriculumStorage;
17445
+ exports.createStreamAbortSignal = createStreamAbortSignal;
17366
17446
  exports.curateMediaLedger = curateMediaLedger;
17367
17447
  exports.designerTools = designerTools;
17368
17448
  exports.detectProjectPedagogy = detectProjectPedagogy;
@@ -17375,6 +17455,7 @@ exports.exportAllProjectQuizzes = exportAllProjectQuizzes;
17375
17455
  exports.expositionCacheKey = expositionCacheKey;
17376
17456
  exports.extractScopeSequenceRows = extractScopeSequenceRows;
17377
17457
  exports.extractSessionSlice = extractSessionSlice;
17458
+ exports.extractStreamChunk = extractStreamChunk;
17378
17459
  exports.extractThoughtAndContent = extractThoughtAndContent;
17379
17460
  exports.formatQuizzesToCsv = formatQuizzesToCsv;
17380
17461
  exports.fulfillMediaLedger = fulfillMediaLedger;
@@ -17457,6 +17538,7 @@ exports.repairMasterLessonStep = repairMasterLessonStep;
17457
17538
  exports.researcherTools = researcherTools;
17458
17539
  exports.resolveGateSettings = resolveGateSettings;
17459
17540
  exports.resolveStandardsPacks = resolveStandardsPacks;
17541
+ exports.resolveStreamBudget = resolveStreamBudget;
17460
17542
  exports.resolveTranslationTargets = resolveTranslationTargets;
17461
17543
  exports.reviewerTools = reviewerTools;
17462
17544
  exports.runCurriculumAIInference = runCurriculumAIInference;