@thanh01.pmt/curriculum-kit 1.4.33 → 1.4.34

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.
@@ -2,8 +2,8 @@ import { M as ModelResolutionOptions } from '../provider-factory-Bv-eIkhg.cjs';
2
2
  export { A as AIProviderName, N as NVIDIA_MODELS, g as getAIModel } from '../provider-factory-Bv-eIkhg.cjs';
3
3
  import { MilestoneInput, LessonPlan, ActivityLab, ProjectGraph, CodeLab, Worksheet, Handout, SlideDeck, TeacherGuide, Extension, CurriculumQualityReport, ProjectInstruction, SelfLab, DiagnosticQuiz } from '../schemas/index.cjs';
4
4
  import * as ai from 'ai';
5
- import { C as ChatMessage, S as StreamRunnerOptions, n as ToolLoopConfig, c as ChunkType } from '../streamRunner-B0Z1nAG5.cjs';
6
- export { A as AggregatedToolCall, D as DEFAULT_ARTIFACT_STREAM_IDLE_MS, d as DEFAULT_ARTIFACT_STREAM_TOTAL_MS, F as FallbackTarget, I as IdleAbort, f as StreamAbortController, T as ToolDefinition, l as ToolExecutionResult, m as ToolExecutor, j as createIdleAbortController, h as createStreamAbortController, e as extractThoughtAndContent, g as getDesignatedFallbackChain, b as getDesignatedFallbackConfig, a as isModelAllowed, i as isProviderEnabled, r as resolveApiKey, k as runCurriculumAIInference, s as streamCurriculumAIInference } from '../streamRunner-B0Z1nAG5.cjs';
5
+ import { a as ChatMessage, S as StreamRunnerOptions, n as ToolLoopConfig, C as ChunkType } from '../streamRunner-BzlJrAGZ.cjs';
6
+ export { A as AggregatedToolCall, D as DEFAULT_ARTIFACT_STREAM_IDLE_MS, d as DEFAULT_ARTIFACT_STREAM_TOTAL_MS, F as FallbackTarget, I as IdleAbort, f as StreamAbortController, T as ToolDefinition, l as ToolExecutionResult, m as ToolExecutor, j as createIdleAbortController, h as createStreamAbortController, e as extractThoughtAndContent, g as getDesignatedFallbackChain, c as getDesignatedFallbackConfig, b as isModelAllowed, i as isProviderEnabled, r as resolveApiKey, k as runCurriculumAIInference, s as streamCurriculumAIInference } from '../streamRunner-BzlJrAGZ.cjs';
7
7
  import { z } from 'zod';
8
8
 
9
9
  interface LessonPromptInput {
@@ -2,8 +2,8 @@ import { M as ModelResolutionOptions } from '../provider-factory-Bv-eIkhg.js';
2
2
  export { A as AIProviderName, N as NVIDIA_MODELS, g as getAIModel } from '../provider-factory-Bv-eIkhg.js';
3
3
  import { MilestoneInput, LessonPlan, ActivityLab, ProjectGraph, CodeLab, Worksheet, Handout, SlideDeck, TeacherGuide, Extension, CurriculumQualityReport, ProjectInstruction, SelfLab, DiagnosticQuiz } from '../schemas/index.js';
4
4
  import * as ai from 'ai';
5
- import { C as ChatMessage, S as StreamRunnerOptions, n as ToolLoopConfig, c as ChunkType } from '../streamRunner-B0Z1nAG5.js';
6
- export { A as AggregatedToolCall, D as DEFAULT_ARTIFACT_STREAM_IDLE_MS, d as DEFAULT_ARTIFACT_STREAM_TOTAL_MS, F as FallbackTarget, I as IdleAbort, f as StreamAbortController, T as ToolDefinition, l as ToolExecutionResult, m as ToolExecutor, j as createIdleAbortController, h as createStreamAbortController, e as extractThoughtAndContent, g as getDesignatedFallbackChain, b as getDesignatedFallbackConfig, a as isModelAllowed, i as isProviderEnabled, r as resolveApiKey, k as runCurriculumAIInference, s as streamCurriculumAIInference } from '../streamRunner-B0Z1nAG5.js';
5
+ import { a as ChatMessage, S as StreamRunnerOptions, n as ToolLoopConfig, C as ChunkType } from '../streamRunner-BzlJrAGZ.js';
6
+ export { A as AggregatedToolCall, D as DEFAULT_ARTIFACT_STREAM_IDLE_MS, d as DEFAULT_ARTIFACT_STREAM_TOTAL_MS, F as FallbackTarget, I as IdleAbort, f as StreamAbortController, T as ToolDefinition, l as ToolExecutionResult, m as ToolExecutor, j as createIdleAbortController, h as createStreamAbortController, e as extractThoughtAndContent, g as getDesignatedFallbackChain, c as getDesignatedFallbackConfig, b as isModelAllowed, i as isProviderEnabled, r as resolveApiKey, k as runCurriculumAIInference, s as streamCurriculumAIInference } from '../streamRunner-BzlJrAGZ.js';
7
7
  import { z } from 'zod';
8
8
 
9
9
  interface LessonPromptInput {
package/dist/index.cjs CHANGED
@@ -29519,7 +29519,7 @@ function safeParseJson(rawText) {
29519
29519
  }
29520
29520
  return null;
29521
29521
  }
29522
- async function streamLLMWithFallback(systemPrompt, userPrompt, apiKeys = {}, onChunk, preferredModel, preferredProvider, budget, signal) {
29522
+ async function streamLLMWithFallback(systemPrompt, userPrompt, apiKeys = {}, onChunk, preferredModel, preferredProvider, budget, signal, onEvent) {
29523
29523
  const alibabaKey = apiKeys.alibaba || apiKeys.dashscope || process.env.ALIBABA_API_KEY || process.env.DASHSCOPE_API_KEY;
29524
29524
  const nvidiaKey = apiKeys.nvidia || process.env.NVIDIA_API_KEY;
29525
29525
  const deepseekKey = apiKeys.deepseek || process.env.DEEPSEEK_API_KEY;
@@ -29600,12 +29600,14 @@ THINKING DIRECTIVE: Do ALL your reasoning internally BEFORE emitting output. Do
29600
29600
  idleMs: budget?.idleMs ?? DEFAULT_STREAM_IDLE_MS,
29601
29601
  totalMs: budget?.totalMs ?? DEFAULT_STREAM_TOTAL_MS
29602
29602
  };
29603
- for (const candidate of candidates) {
29603
+ for (const [candidateIdx, candidate] of candidates.entries()) {
29604
29604
  if (signal?.aborted) {
29605
29605
  console.log(`[curriculum-kit:VercelAI] AbortSignal already aborted, cancelling candidate loop.`);
29606
29606
  break;
29607
29607
  }
29608
29608
  const t0 = Date.now();
29609
+ const attempt = candidateIdx + 1;
29610
+ onEvent?.({ type: "candidate-start", provider: candidate.provider, model: candidate.model, attempt, total: candidates.length, elapsedMs: 0 });
29609
29611
  const abort = createStreamAbortSignal(resolvedBudget, signal);
29610
29612
  try {
29611
29613
  const modelInstance = getAIModel({
@@ -29613,18 +29615,35 @@ THINKING DIRECTIVE: Do ALL your reasoning internally BEFORE emitting output. Do
29613
29615
  modelName: candidate.model,
29614
29616
  apiKey: candidate.apiKey
29615
29617
  });
29618
+ const wireFetch = (input, init) => fetch(input, init).then((res) => {
29619
+ if (!res.body) return res;
29620
+ const kicked = res.body.pipeThrough(
29621
+ new TransformStream({
29622
+ transform(chunk, ctrl) {
29623
+ abort.kick();
29624
+ ctrl.enqueue(chunk);
29625
+ }
29626
+ })
29627
+ );
29628
+ return new Response(kicked, res);
29629
+ });
29616
29630
  const streamResult = ai.streamText({
29617
29631
  model: modelInstance,
29618
29632
  system: systemInstructions,
29619
29633
  prompt: userPrompt,
29620
29634
  temperature: 0.2,
29621
29635
  includeRawChunks: true,
29622
- abortSignal: abort.signal
29636
+ abortSignal: abort.signal,
29637
+ fetch: wireFetch
29623
29638
  });
29624
29639
  let fullContent = "";
29625
29640
  const extract = createStreamChunkExtractor();
29626
29641
  for await (const part of streamResult.fullStream) {
29627
29642
  abort.kick();
29643
+ if (part?.type === "error") {
29644
+ const errText = part.errorText ?? String(part.error ?? "unknown stream error");
29645
+ throw new Error(`[${candidate.provider}] stream error part: ${errText}`);
29646
+ }
29628
29647
  const extracted = extract(part);
29629
29648
  if (extracted.thought) onChunk?.(extracted.thought, "thought");
29630
29649
  if (extracted.content) {
@@ -29634,10 +29653,14 @@ THINKING DIRECTIVE: Do ALL your reasoning internally BEFORE emitting output. Do
29634
29653
  }
29635
29654
  if (fullContent.trim()) {
29636
29655
  console.log(`[curriculum-kit:VercelAI] \u2705 ${candidate.provider} (${candidate.model}) streamed in ${Date.now() - t0}ms`);
29656
+ onEvent?.({ type: "candidate-success", provider: candidate.provider, model: candidate.model, attempt, total: candidates.length, elapsedMs: Date.now() - t0 });
29637
29657
  return fullContent.trim();
29638
29658
  }
29659
+ console.warn(`[curriculum-kit:VercelAI] Candidate ${candidate.provider} (${candidate.model}) returned EMPTY content in ${Date.now() - t0}ms \u2192 trying next candidate.`);
29660
+ onEvent?.({ type: "candidate-failed", provider: candidate.provider, model: candidate.model, attempt, total: candidates.length, elapsedMs: Date.now() - t0, error: "empty content" });
29639
29661
  } catch (e) {
29640
29662
  console.warn(`[curriculum-kit:VercelAI] Candidate ${candidate.provider} (${candidate.model}) failed in ${Date.now() - t0}ms:`, e?.message || e);
29663
+ onEvent?.({ type: "candidate-failed", provider: candidate.provider, model: candidate.model, attempt, total: candidates.length, elapsedMs: Date.now() - t0, error: e?.message || String(e) });
29641
29664
  const isClientAborted = Boolean(
29642
29665
  signal?.aborted || e?.name === "AbortError" && signal?.aborted || e?.message && (e.message.includes("Controller is already closed") || e.message.includes("The operation was aborted") || e.message.includes("Aborted by parent signal"))
29643
29666
  );
@@ -29697,7 +29720,8 @@ Return concise JSON matching:
29697
29720
  model: options.model,
29698
29721
  provider: options.provider
29699
29722
  }),
29700
- options.signal
29723
+ options.signal,
29724
+ options.onProviderEvent
29701
29725
  );
29702
29726
  let parsedResearch = {
29703
29727
  groundTruthSummary: `Verified ecosystem standards for ${projectName}`,
@@ -29779,6 +29803,23 @@ async function streamLayerPrefillWithFallback(options, onChunk) {
29779
29803
  const research = await conductPreliminaryResearch(options, onChunk);
29780
29804
  return { success: true, research };
29781
29805
  }
29806
+ const runWithCustomInference = async (systemInstruction, userPrompt2) => {
29807
+ if (!options.customInference) return "";
29808
+ return options.customInference({
29809
+ systemInstruction,
29810
+ userPrompt: userPrompt2,
29811
+ messages: [{ role: "user", content: userPrompt2 }],
29812
+ temperature: 0.2,
29813
+ // Layer 3 synthesizes full context — give reasoning models the same
29814
+ // generous ceiling the artifact paths use (32k) so JSON is never truncated.
29815
+ maxTokens: 32768,
29816
+ onChunk: (token, type) => {
29817
+ if (type === "content") rawContent += token;
29818
+ if (type === "content" || type === "thought") onChunk?.(token, type);
29819
+ }
29820
+ });
29821
+ };
29822
+ let rawContent = "";
29782
29823
  const {
29783
29824
  projectName = "Curriculum Course",
29784
29825
  projectCode = "curriculum-course",
@@ -29890,27 +29931,31 @@ FULL ACCUMULATED CONTEXT (ALL CONFIRMED PARAMETERS FROM EVERY PREVIOUS STEP \u20
29890
29931
  ${buildRemainingContextBlock(accumulatedData) || "(no additional context)"}
29891
29932
 
29892
29933
  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}.`;
29893
- let rawContent = "";
29894
- await streamLLMWithFallback(
29895
- systemPrompt,
29896
- userPrompt,
29897
- apiKeys,
29898
- (chunk, type) => {
29899
- if (type === "content") rawContent += chunk;
29900
- onChunk?.(chunk, type);
29901
- },
29902
- options.model,
29903
- options.provider,
29904
- // RC-W1: layer-aware budget — Layer 3 synthesizes full context and free-tier
29905
- // models (especially NVIDIA NIM) may think/stream for minutes. Idle window still catches hangs.
29906
- resolveStreamBudget(targetLayer, {
29907
- idleMs: options.idleTimeoutMs,
29908
- totalMs: options.timeoutMs,
29909
- model: options.model,
29910
- provider: options.provider
29911
- }),
29912
- options.signal
29913
- );
29934
+ if (options.customInference) {
29935
+ rawContent = await runWithCustomInference(systemPrompt, userPrompt) || "";
29936
+ } else {
29937
+ await streamLLMWithFallback(
29938
+ systemPrompt,
29939
+ userPrompt,
29940
+ apiKeys,
29941
+ (chunk, type) => {
29942
+ if (type === "content") rawContent += chunk;
29943
+ onChunk?.(chunk, type);
29944
+ },
29945
+ options.model,
29946
+ options.provider,
29947
+ // RC-W1: layer-aware budget — Layer 3 synthesizes full context and free-tier
29948
+ // models (especially NVIDIA NIM) may think/stream for minutes. Idle window still catches hangs.
29949
+ resolveStreamBudget(targetLayer, {
29950
+ idleMs: options.idleTimeoutMs,
29951
+ totalMs: options.timeoutMs,
29952
+ model: options.model,
29953
+ provider: options.provider
29954
+ }),
29955
+ options.signal,
29956
+ options.onProviderEvent
29957
+ );
29958
+ }
29914
29959
  const parsed = safeParseJson(rawContent);
29915
29960
  return {
29916
29961
  success: !!parsed,