@thanh01.pmt/curriculum-kit 1.4.32 → 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.
- package/dist/ai/index.cjs +48 -1
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.d.cts +2 -2
- package/dist/ai/index.d.ts +2 -2
- package/dist/ai/index.mjs +48 -1
- package/dist/ai/index.mjs.map +1 -1
- package/dist/index.cjs +118 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -4
- package/dist/index.d.ts +36 -4
- package/dist/index.mjs +118 -26
- package/dist/index.mjs.map +1 -1
- package/dist/media/index.d.cts +1 -1
- package/dist/media/index.d.ts +1 -1
- package/dist/pipeline/index.cjs +48 -1
- package/dist/pipeline/index.cjs.map +1 -1
- package/dist/pipeline/index.mjs +48 -1
- package/dist/pipeline/index.mjs.map +1 -1
- package/dist/{streamRunner-B0Z1nAG5.d.cts → streamRunner-BzlJrAGZ.d.cts} +1 -1
- package/dist/{streamRunner-B0Z1nAG5.d.ts → streamRunner-BzlJrAGZ.d.ts} +1 -1
- package/dist/workflow/index.cjs +48 -1
- package/dist/workflow/index.cjs.map +1 -1
- package/dist/workflow/index.mjs +48 -1
- package/dist/workflow/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -991,6 +991,52 @@ var init_streamRunner = __esm({
|
|
|
991
991
|
exports.DEFAULT_ARTIFACT_STREAM_TOTAL_MS = 48e4;
|
|
992
992
|
}
|
|
993
993
|
});
|
|
994
|
+
function cleanNonStreamingFetch() {
|
|
995
|
+
return async (input, init) => {
|
|
996
|
+
const res = await fetch(input, init);
|
|
997
|
+
let wantsStream = false;
|
|
998
|
+
try {
|
|
999
|
+
const body = init?.body;
|
|
1000
|
+
if (typeof body === "string") wantsStream = /"stream"\s*:\s*true/.test(body);
|
|
1001
|
+
} catch {
|
|
1002
|
+
}
|
|
1003
|
+
if (wantsStream) return res;
|
|
1004
|
+
const contentType = res.headers.get("content-type") || "";
|
|
1005
|
+
if (!contentType.includes("text/event-stream") && !contentType.includes("application/json")) return res;
|
|
1006
|
+
const text = await res.text();
|
|
1007
|
+
const trimmed = text.trim();
|
|
1008
|
+
if (trimmed.startsWith("data:")) {
|
|
1009
|
+
let content = "";
|
|
1010
|
+
let lastChunk = null;
|
|
1011
|
+
for (const line of trimmed.split("\n")) {
|
|
1012
|
+
const l = line.trim();
|
|
1013
|
+
if (!l || !l.startsWith("data:")) continue;
|
|
1014
|
+
const jsonStr = l.slice(5).trim();
|
|
1015
|
+
if (jsonStr === "[DONE]") continue;
|
|
1016
|
+
try {
|
|
1017
|
+
const chunk = JSON.parse(jsonStr);
|
|
1018
|
+
lastChunk = chunk;
|
|
1019
|
+
content += chunk.choices?.[0]?.delta?.content || "";
|
|
1020
|
+
} catch {
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
const assembled = {
|
|
1024
|
+
id: lastChunk?.id || "chatcmpl-" + Date.now(),
|
|
1025
|
+
object: "chat.completion",
|
|
1026
|
+
created: lastChunk?.created || Math.floor(Date.now() / 1e3),
|
|
1027
|
+
model: lastChunk?.model || "9router",
|
|
1028
|
+
choices: [{ index: 0, message: { role: "assistant", content }, finish_reason: "stop" }],
|
|
1029
|
+
usage: lastChunk?.usage || void 0
|
|
1030
|
+
};
|
|
1031
|
+
const headers = new Headers(res.headers);
|
|
1032
|
+
headers.set("content-type", "application/json");
|
|
1033
|
+
return new Response(JSON.stringify(assembled), { status: res.status, statusText: res.statusText, headers });
|
|
1034
|
+
}
|
|
1035
|
+
const doneIndex = text.indexOf("data: [DONE]");
|
|
1036
|
+
if (doneIndex === -1) return res;
|
|
1037
|
+
return new Response(text.slice(0, doneIndex).trim(), { status: res.status, statusText: res.statusText, headers: res.headers });
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
994
1040
|
function getAIModel(options = {}) {
|
|
995
1041
|
const designated = getDesignatedFallbackConfig();
|
|
996
1042
|
const defaultProvider = process.env.DEFAULT_AI_PROVIDER || process.env.LLM_PROVIDER || detectDefaultProvider();
|
|
@@ -1009,7 +1055,8 @@ function getAIModel(options = {}) {
|
|
|
1009
1055
|
const rawUrl = options.baseURL || resolveApiKey("NINEROUTER_BASE_URL") || resolveApiKey("NINE_ROUTER_BASE_URL") || "https://ai-router.orchable.app/v1";
|
|
1010
1056
|
const ninerouter = openai.createOpenAI({
|
|
1011
1057
|
apiKey,
|
|
1012
|
-
baseURL: rawUrl.replace(/^["']|["']$/g, "").trim()
|
|
1058
|
+
baseURL: rawUrl.replace(/^["']|["']$/g, "").trim(),
|
|
1059
|
+
fetch: cleanNonStreamingFetch()
|
|
1013
1060
|
});
|
|
1014
1061
|
return ninerouter.chat(resolvedModelName || "fast-reasoning");
|
|
1015
1062
|
}
|
|
@@ -29472,7 +29519,7 @@ function safeParseJson(rawText) {
|
|
|
29472
29519
|
}
|
|
29473
29520
|
return null;
|
|
29474
29521
|
}
|
|
29475
|
-
async function streamLLMWithFallback(systemPrompt, userPrompt, apiKeys = {}, onChunk, preferredModel, preferredProvider, budget, signal) {
|
|
29522
|
+
async function streamLLMWithFallback(systemPrompt, userPrompt, apiKeys = {}, onChunk, preferredModel, preferredProvider, budget, signal, onEvent) {
|
|
29476
29523
|
const alibabaKey = apiKeys.alibaba || apiKeys.dashscope || process.env.ALIBABA_API_KEY || process.env.DASHSCOPE_API_KEY;
|
|
29477
29524
|
const nvidiaKey = apiKeys.nvidia || process.env.NVIDIA_API_KEY;
|
|
29478
29525
|
const deepseekKey = apiKeys.deepseek || process.env.DEEPSEEK_API_KEY;
|
|
@@ -29553,12 +29600,14 @@ THINKING DIRECTIVE: Do ALL your reasoning internally BEFORE emitting output. Do
|
|
|
29553
29600
|
idleMs: budget?.idleMs ?? DEFAULT_STREAM_IDLE_MS,
|
|
29554
29601
|
totalMs: budget?.totalMs ?? DEFAULT_STREAM_TOTAL_MS
|
|
29555
29602
|
};
|
|
29556
|
-
for (const candidate of candidates) {
|
|
29603
|
+
for (const [candidateIdx, candidate] of candidates.entries()) {
|
|
29557
29604
|
if (signal?.aborted) {
|
|
29558
29605
|
console.log(`[curriculum-kit:VercelAI] AbortSignal already aborted, cancelling candidate loop.`);
|
|
29559
29606
|
break;
|
|
29560
29607
|
}
|
|
29561
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 });
|
|
29562
29611
|
const abort = createStreamAbortSignal(resolvedBudget, signal);
|
|
29563
29612
|
try {
|
|
29564
29613
|
const modelInstance = getAIModel({
|
|
@@ -29566,18 +29615,35 @@ THINKING DIRECTIVE: Do ALL your reasoning internally BEFORE emitting output. Do
|
|
|
29566
29615
|
modelName: candidate.model,
|
|
29567
29616
|
apiKey: candidate.apiKey
|
|
29568
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
|
+
});
|
|
29569
29630
|
const streamResult = ai.streamText({
|
|
29570
29631
|
model: modelInstance,
|
|
29571
29632
|
system: systemInstructions,
|
|
29572
29633
|
prompt: userPrompt,
|
|
29573
29634
|
temperature: 0.2,
|
|
29574
29635
|
includeRawChunks: true,
|
|
29575
|
-
abortSignal: abort.signal
|
|
29636
|
+
abortSignal: abort.signal,
|
|
29637
|
+
fetch: wireFetch
|
|
29576
29638
|
});
|
|
29577
29639
|
let fullContent = "";
|
|
29578
29640
|
const extract = createStreamChunkExtractor();
|
|
29579
29641
|
for await (const part of streamResult.fullStream) {
|
|
29580
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
|
+
}
|
|
29581
29647
|
const extracted = extract(part);
|
|
29582
29648
|
if (extracted.thought) onChunk?.(extracted.thought, "thought");
|
|
29583
29649
|
if (extracted.content) {
|
|
@@ -29587,10 +29653,14 @@ THINKING DIRECTIVE: Do ALL your reasoning internally BEFORE emitting output. Do
|
|
|
29587
29653
|
}
|
|
29588
29654
|
if (fullContent.trim()) {
|
|
29589
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 });
|
|
29590
29657
|
return fullContent.trim();
|
|
29591
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" });
|
|
29592
29661
|
} catch (e) {
|
|
29593
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) });
|
|
29594
29664
|
const isClientAborted = Boolean(
|
|
29595
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"))
|
|
29596
29666
|
);
|
|
@@ -29650,7 +29720,8 @@ Return concise JSON matching:
|
|
|
29650
29720
|
model: options.model,
|
|
29651
29721
|
provider: options.provider
|
|
29652
29722
|
}),
|
|
29653
|
-
options.signal
|
|
29723
|
+
options.signal,
|
|
29724
|
+
options.onProviderEvent
|
|
29654
29725
|
);
|
|
29655
29726
|
let parsedResearch = {
|
|
29656
29727
|
groundTruthSummary: `Verified ecosystem standards for ${projectName}`,
|
|
@@ -29732,6 +29803,23 @@ async function streamLayerPrefillWithFallback(options, onChunk) {
|
|
|
29732
29803
|
const research = await conductPreliminaryResearch(options, onChunk);
|
|
29733
29804
|
return { success: true, research };
|
|
29734
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 = "";
|
|
29735
29823
|
const {
|
|
29736
29824
|
projectName = "Curriculum Course",
|
|
29737
29825
|
projectCode = "curriculum-course",
|
|
@@ -29843,27 +29931,31 @@ FULL ACCUMULATED CONTEXT (ALL CONFIRMED PARAMETERS FROM EVERY PREVIOUS STEP \u20
|
|
|
29843
29931
|
${buildRemainingContextBlock(accumulatedData) || "(no additional context)"}
|
|
29844
29932
|
|
|
29845
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}.`;
|
|
29846
|
-
|
|
29847
|
-
|
|
29848
|
-
|
|
29849
|
-
|
|
29850
|
-
|
|
29851
|
-
|
|
29852
|
-
|
|
29853
|
-
|
|
29854
|
-
|
|
29855
|
-
|
|
29856
|
-
|
|
29857
|
-
|
|
29858
|
-
|
|
29859
|
-
|
|
29860
|
-
|
|
29861
|
-
|
|
29862
|
-
|
|
29863
|
-
|
|
29864
|
-
|
|
29865
|
-
|
|
29866
|
-
|
|
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
|
+
}
|
|
29867
29959
|
const parsed = safeParseJson(rawContent);
|
|
29868
29960
|
return {
|
|
29869
29961
|
success: !!parsed,
|