@thanh01.pmt/curriculum-kit 1.4.31 → 1.4.33
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 +126 -1
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.d.cts +10 -46
- package/dist/ai/index.d.ts +10 -46
- package/dist/ai/index.mjs +126 -1
- package/dist/ai/index.mjs.map +1 -1
- package/dist/index.cjs +128 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +128 -1
- package/dist/index.mjs.map +1 -1
- package/dist/media/index.cjs.map +1 -1
- package/dist/media/index.d.cts +1 -1
- package/dist/media/index.d.ts +1 -1
- package/dist/media/index.mjs.map +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-DYHFhNUr.d.cts → streamRunner-B0Z1nAG5.d.cts} +76 -1
- package/dist/{streamRunner-DYHFhNUr.d.ts → streamRunner-B0Z1nAG5.d.ts} +76 -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
|
}
|
|
@@ -7937,6 +7984,8 @@ var LLMJudgeEngine = class {
|
|
|
7937
7984
|
};
|
|
7938
7985
|
|
|
7939
7986
|
// src/ai/chatToolLoop.ts
|
|
7987
|
+
init_streamRunner();
|
|
7988
|
+
init_errors();
|
|
7940
7989
|
var PROVIDER_ENDPOINTS = {
|
|
7941
7990
|
openrouter: "https://openrouter.ai/api/v1/chat/completions",
|
|
7942
7991
|
deepseek: "https://api.deepseek.com/chat/completions",
|
|
@@ -8070,6 +8119,16 @@ async function runTurn(endpoint, model, apiKey, messages, tools, idleTimeoutMs,
|
|
|
8070
8119
|
return { content: fullRaw, toolCalls };
|
|
8071
8120
|
}
|
|
8072
8121
|
async function streamCurriculumAIInferenceWithTools(messages, projectContext, options, loop, onChunk) {
|
|
8122
|
+
if (options.customToolInference) {
|
|
8123
|
+
return runToolLoopWithCustomInference(messages, projectContext, options, loop, onChunk);
|
|
8124
|
+
}
|
|
8125
|
+
if (resolveApiKey("CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE") === "1") {
|
|
8126
|
+
throw createAiInferenceError({
|
|
8127
|
+
errorCode: "ERR_CUSTOM_INFERENCE_REQUIRED",
|
|
8128
|
+
message: "customToolInference is REQUIRED (CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE=1): pass buildKitToolInference(...) so tool-calling turns flow through the host AI SDK gateway and its unified Langfuse tracing. Raw-fetch tool-loop provider routes are disabled by mandate.",
|
|
8129
|
+
rawError: { mandate: "CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE", hasCustomToolInference: false }
|
|
8130
|
+
});
|
|
8131
|
+
}
|
|
8073
8132
|
const route = resolveProviderRoute(options);
|
|
8074
8133
|
const maxTokens = options.maxTokens ?? 32768;
|
|
8075
8134
|
const maxRounds = loop.maxRounds ?? 4;
|
|
@@ -8134,6 +8193,74 @@ Guidelines:
|
|
|
8134
8193
|
}
|
|
8135
8194
|
return finalContent;
|
|
8136
8195
|
}
|
|
8196
|
+
async function runToolLoopWithCustomInference(messages, projectContext, options, loop, onChunk) {
|
|
8197
|
+
const infer = options.customToolInference;
|
|
8198
|
+
const maxTokens = options.maxTokens ?? 32768;
|
|
8199
|
+
const maxRounds = loop.maxRounds ?? 4;
|
|
8200
|
+
const systemInstruction = `${options.systemPersona || "You are Curriculum OS Assistant."}
|
|
8201
|
+
|
|
8202
|
+
Project Context:
|
|
8203
|
+
${projectContext}
|
|
8204
|
+
|
|
8205
|
+
Guidelines:
|
|
8206
|
+
1. Answer precisely using the provided tools when they help (project status, deep research, production declaration, gate approval).
|
|
8207
|
+
2. Keep Markdown formatting. Never invent tool results.`;
|
|
8208
|
+
const convo = [
|
|
8209
|
+
{ role: "system", content: systemInstruction },
|
|
8210
|
+
...messages.map((m) => ({ role: m.role === "assistant" || m.role === "model" ? "assistant" : "user", content: m.content }))
|
|
8211
|
+
];
|
|
8212
|
+
let finalContent = "";
|
|
8213
|
+
for (let round = 0; round < maxRounds; round++) {
|
|
8214
|
+
let turn;
|
|
8215
|
+
try {
|
|
8216
|
+
turn = await infer({ messages: convo, tools: loop.tools, temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
|
|
8217
|
+
}) });
|
|
8218
|
+
} catch (err) {
|
|
8219
|
+
const msg = String(err?.message || err);
|
|
8220
|
+
if (/tool/i.test(msg) && /40[04]|400|not support|invalid/i.test(msg)) {
|
|
8221
|
+
console.warn("[toolLoop] custom gateway rejected tools \u2014 degrading to plain chat:", msg.slice(0, 120));
|
|
8222
|
+
const plain = await infer({ messages: convo, tools: [], temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
|
|
8223
|
+
}) });
|
|
8224
|
+
finalContent = plain.content;
|
|
8225
|
+
break;
|
|
8226
|
+
}
|
|
8227
|
+
throw err;
|
|
8228
|
+
}
|
|
8229
|
+
const { content, toolCalls } = turn;
|
|
8230
|
+
if (toolCalls.length === 0) {
|
|
8231
|
+
finalContent = content;
|
|
8232
|
+
break;
|
|
8233
|
+
}
|
|
8234
|
+
if (content) finalContent = content;
|
|
8235
|
+
convo.push({ role: "assistant", content: content || null, tool_calls: toolCalls.map((t) => ({ id: t.id, type: "function", function: { name: t.name, arguments: t.arguments } })) });
|
|
8236
|
+
for (const call of toolCalls) {
|
|
8237
|
+
let parsedArgs = {};
|
|
8238
|
+
try {
|
|
8239
|
+
parsedArgs = JSON.parse(call.arguments || "{}");
|
|
8240
|
+
} catch {
|
|
8241
|
+
}
|
|
8242
|
+
loop.onToolStart?.(call.name, parsedArgs);
|
|
8243
|
+
let resultPayload;
|
|
8244
|
+
let isError = false;
|
|
8245
|
+
try {
|
|
8246
|
+
resultPayload = await loop.executor(call.name, parsedArgs);
|
|
8247
|
+
} catch (err) {
|
|
8248
|
+
isError = true;
|
|
8249
|
+
resultPayload = { error: err?.message || String(err) };
|
|
8250
|
+
loop.onToolError?.(call.name, err?.message || String(err));
|
|
8251
|
+
}
|
|
8252
|
+
const exec = { toolCallId: call.id, name: call.name, result: resultPayload, isError };
|
|
8253
|
+
loop.onToolResult?.(exec);
|
|
8254
|
+
convo.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify(resultPayload).slice(0, 12e3) });
|
|
8255
|
+
}
|
|
8256
|
+
if (round === maxRounds - 1) {
|
|
8257
|
+
const last = await infer({ messages: convo, tools: [], temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
|
|
8258
|
+
}) });
|
|
8259
|
+
finalContent = last.content;
|
|
8260
|
+
}
|
|
8261
|
+
}
|
|
8262
|
+
return finalContent;
|
|
8263
|
+
}
|
|
8137
8264
|
|
|
8138
8265
|
// src/pipeline/markdownSerializers.ts
|
|
8139
8266
|
function serializeLessonToMarkdown(lesson) {
|