@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/ai/index.cjs
CHANGED
|
@@ -933,6 +933,52 @@ async function runCurriculumAIInference(messages, projectContext, options = {},
|
|
|
933
933
|
}
|
|
934
934
|
|
|
935
935
|
// src/ai/provider-factory.ts
|
|
936
|
+
function cleanNonStreamingFetch() {
|
|
937
|
+
return async (input, init) => {
|
|
938
|
+
const res = await fetch(input, init);
|
|
939
|
+
let wantsStream = false;
|
|
940
|
+
try {
|
|
941
|
+
const body = init?.body;
|
|
942
|
+
if (typeof body === "string") wantsStream = /"stream"\s*:\s*true/.test(body);
|
|
943
|
+
} catch {
|
|
944
|
+
}
|
|
945
|
+
if (wantsStream) return res;
|
|
946
|
+
const contentType = res.headers.get("content-type") || "";
|
|
947
|
+
if (!contentType.includes("text/event-stream") && !contentType.includes("application/json")) return res;
|
|
948
|
+
const text = await res.text();
|
|
949
|
+
const trimmed = text.trim();
|
|
950
|
+
if (trimmed.startsWith("data:")) {
|
|
951
|
+
let content = "";
|
|
952
|
+
let lastChunk = null;
|
|
953
|
+
for (const line of trimmed.split("\n")) {
|
|
954
|
+
const l = line.trim();
|
|
955
|
+
if (!l || !l.startsWith("data:")) continue;
|
|
956
|
+
const jsonStr = l.slice(5).trim();
|
|
957
|
+
if (jsonStr === "[DONE]") continue;
|
|
958
|
+
try {
|
|
959
|
+
const chunk = JSON.parse(jsonStr);
|
|
960
|
+
lastChunk = chunk;
|
|
961
|
+
content += chunk.choices?.[0]?.delta?.content || "";
|
|
962
|
+
} catch {
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
const assembled = {
|
|
966
|
+
id: lastChunk?.id || "chatcmpl-" + Date.now(),
|
|
967
|
+
object: "chat.completion",
|
|
968
|
+
created: lastChunk?.created || Math.floor(Date.now() / 1e3),
|
|
969
|
+
model: lastChunk?.model || "9router",
|
|
970
|
+
choices: [{ index: 0, message: { role: "assistant", content }, finish_reason: "stop" }],
|
|
971
|
+
usage: lastChunk?.usage || void 0
|
|
972
|
+
};
|
|
973
|
+
const headers = new Headers(res.headers);
|
|
974
|
+
headers.set("content-type", "application/json");
|
|
975
|
+
return new Response(JSON.stringify(assembled), { status: res.status, statusText: res.statusText, headers });
|
|
976
|
+
}
|
|
977
|
+
const doneIndex = text.indexOf("data: [DONE]");
|
|
978
|
+
if (doneIndex === -1) return res;
|
|
979
|
+
return new Response(text.slice(0, doneIndex).trim(), { status: res.status, statusText: res.statusText, headers: res.headers });
|
|
980
|
+
};
|
|
981
|
+
}
|
|
936
982
|
var DEFAULT_MODELS = {
|
|
937
983
|
"9router": "fast-reasoning",
|
|
938
984
|
ninerouter: "fast-reasoning",
|
|
@@ -972,7 +1018,8 @@ function getAIModel(options = {}) {
|
|
|
972
1018
|
const rawUrl = options.baseURL || resolveApiKey("NINEROUTER_BASE_URL") || resolveApiKey("NINE_ROUTER_BASE_URL") || "https://ai-router.orchable.app/v1";
|
|
973
1019
|
const ninerouter = openai.createOpenAI({
|
|
974
1020
|
apiKey,
|
|
975
|
-
baseURL: rawUrl.replace(/^["']|["']$/g, "").trim()
|
|
1021
|
+
baseURL: rawUrl.replace(/^["']|["']$/g, "").trim(),
|
|
1022
|
+
fetch: cleanNonStreamingFetch()
|
|
976
1023
|
});
|
|
977
1024
|
return ninerouter.chat(resolvedModelName || "fast-reasoning");
|
|
978
1025
|
}
|
|
@@ -5129,6 +5176,16 @@ async function runTurn(endpoint, model, apiKey, messages, tools, idleTimeoutMs,
|
|
|
5129
5176
|
return { content: fullRaw, toolCalls };
|
|
5130
5177
|
}
|
|
5131
5178
|
async function streamCurriculumAIInferenceWithTools(messages, projectContext, options, loop, onChunk) {
|
|
5179
|
+
if (options.customToolInference) {
|
|
5180
|
+
return runToolLoopWithCustomInference(messages, projectContext, options, loop, onChunk);
|
|
5181
|
+
}
|
|
5182
|
+
if (resolveApiKey("CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE") === "1") {
|
|
5183
|
+
throw createAiInferenceError({
|
|
5184
|
+
errorCode: "ERR_CUSTOM_INFERENCE_REQUIRED",
|
|
5185
|
+
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.",
|
|
5186
|
+
rawError: { mandate: "CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE", hasCustomToolInference: false }
|
|
5187
|
+
});
|
|
5188
|
+
}
|
|
5132
5189
|
const route = resolveProviderRoute(options);
|
|
5133
5190
|
const maxTokens = options.maxTokens ?? 32768;
|
|
5134
5191
|
const maxRounds = loop.maxRounds ?? 4;
|
|
@@ -5193,6 +5250,74 @@ Guidelines:
|
|
|
5193
5250
|
}
|
|
5194
5251
|
return finalContent;
|
|
5195
5252
|
}
|
|
5253
|
+
async function runToolLoopWithCustomInference(messages, projectContext, options, loop, onChunk) {
|
|
5254
|
+
const infer = options.customToolInference;
|
|
5255
|
+
const maxTokens = options.maxTokens ?? 32768;
|
|
5256
|
+
const maxRounds = loop.maxRounds ?? 4;
|
|
5257
|
+
const systemInstruction = `${options.systemPersona || "You are Curriculum OS Assistant."}
|
|
5258
|
+
|
|
5259
|
+
Project Context:
|
|
5260
|
+
${projectContext}
|
|
5261
|
+
|
|
5262
|
+
Guidelines:
|
|
5263
|
+
1. Answer precisely using the provided tools when they help (project status, deep research, production declaration, gate approval).
|
|
5264
|
+
2. Keep Markdown formatting. Never invent tool results.`;
|
|
5265
|
+
const convo = [
|
|
5266
|
+
{ role: "system", content: systemInstruction },
|
|
5267
|
+
...messages.map((m) => ({ role: m.role === "assistant" || m.role === "model" ? "assistant" : "user", content: m.content }))
|
|
5268
|
+
];
|
|
5269
|
+
let finalContent = "";
|
|
5270
|
+
for (let round = 0; round < maxRounds; round++) {
|
|
5271
|
+
let turn;
|
|
5272
|
+
try {
|
|
5273
|
+
turn = await infer({ messages: convo, tools: loop.tools, temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
|
|
5274
|
+
}) });
|
|
5275
|
+
} catch (err) {
|
|
5276
|
+
const msg = String(err?.message || err);
|
|
5277
|
+
if (/tool/i.test(msg) && /40[04]|400|not support|invalid/i.test(msg)) {
|
|
5278
|
+
console.warn("[toolLoop] custom gateway rejected tools \u2014 degrading to plain chat:", msg.slice(0, 120));
|
|
5279
|
+
const plain = await infer({ messages: convo, tools: [], temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
|
|
5280
|
+
}) });
|
|
5281
|
+
finalContent = plain.content;
|
|
5282
|
+
break;
|
|
5283
|
+
}
|
|
5284
|
+
throw err;
|
|
5285
|
+
}
|
|
5286
|
+
const { content, toolCalls } = turn;
|
|
5287
|
+
if (toolCalls.length === 0) {
|
|
5288
|
+
finalContent = content;
|
|
5289
|
+
break;
|
|
5290
|
+
}
|
|
5291
|
+
if (content) finalContent = content;
|
|
5292
|
+
convo.push({ role: "assistant", content: content || null, tool_calls: toolCalls.map((t) => ({ id: t.id, type: "function", function: { name: t.name, arguments: t.arguments } })) });
|
|
5293
|
+
for (const call of toolCalls) {
|
|
5294
|
+
let parsedArgs = {};
|
|
5295
|
+
try {
|
|
5296
|
+
parsedArgs = JSON.parse(call.arguments || "{}");
|
|
5297
|
+
} catch {
|
|
5298
|
+
}
|
|
5299
|
+
loop.onToolStart?.(call.name, parsedArgs);
|
|
5300
|
+
let resultPayload;
|
|
5301
|
+
let isError = false;
|
|
5302
|
+
try {
|
|
5303
|
+
resultPayload = await loop.executor(call.name, parsedArgs);
|
|
5304
|
+
} catch (err) {
|
|
5305
|
+
isError = true;
|
|
5306
|
+
resultPayload = { error: err?.message || String(err) };
|
|
5307
|
+
loop.onToolError?.(call.name, err?.message || String(err));
|
|
5308
|
+
}
|
|
5309
|
+
const exec = { toolCallId: call.id, name: call.name, result: resultPayload, isError };
|
|
5310
|
+
loop.onToolResult?.(exec);
|
|
5311
|
+
convo.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify(resultPayload).slice(0, 12e3) });
|
|
5312
|
+
}
|
|
5313
|
+
if (round === maxRounds - 1) {
|
|
5314
|
+
const last = await infer({ messages: convo, tools: [], temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
|
|
5315
|
+
}) });
|
|
5316
|
+
finalContent = last.content;
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5319
|
+
return finalContent;
|
|
5320
|
+
}
|
|
5196
5321
|
|
|
5197
5322
|
exports.DEFAULT_ARTIFACT_STREAM_IDLE_MS = DEFAULT_ARTIFACT_STREAM_IDLE_MS;
|
|
5198
5323
|
exports.DEFAULT_ARTIFACT_STREAM_TOTAL_MS = DEFAULT_ARTIFACT_STREAM_TOTAL_MS;
|