@thanh01.pmt/curriculum-kit 1.4.30 → 1.4.32

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 CHANGED
@@ -5129,6 +5129,16 @@ async function runTurn(endpoint, model, apiKey, messages, tools, idleTimeoutMs,
5129
5129
  return { content: fullRaw, toolCalls };
5130
5130
  }
5131
5131
  async function streamCurriculumAIInferenceWithTools(messages, projectContext, options, loop, onChunk) {
5132
+ if (options.customToolInference) {
5133
+ return runToolLoopWithCustomInference(messages, projectContext, options, loop, onChunk);
5134
+ }
5135
+ if (resolveApiKey("CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE") === "1") {
5136
+ throw createAiInferenceError({
5137
+ errorCode: "ERR_CUSTOM_INFERENCE_REQUIRED",
5138
+ 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.",
5139
+ rawError: { mandate: "CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE", hasCustomToolInference: false }
5140
+ });
5141
+ }
5132
5142
  const route = resolveProviderRoute(options);
5133
5143
  const maxTokens = options.maxTokens ?? 32768;
5134
5144
  const maxRounds = loop.maxRounds ?? 4;
@@ -5193,6 +5203,74 @@ Guidelines:
5193
5203
  }
5194
5204
  return finalContent;
5195
5205
  }
5206
+ async function runToolLoopWithCustomInference(messages, projectContext, options, loop, onChunk) {
5207
+ const infer = options.customToolInference;
5208
+ const maxTokens = options.maxTokens ?? 32768;
5209
+ const maxRounds = loop.maxRounds ?? 4;
5210
+ const systemInstruction = `${options.systemPersona || "You are Curriculum OS Assistant."}
5211
+
5212
+ Project Context:
5213
+ ${projectContext}
5214
+
5215
+ Guidelines:
5216
+ 1. Answer precisely using the provided tools when they help (project status, deep research, production declaration, gate approval).
5217
+ 2. Keep Markdown formatting. Never invent tool results.`;
5218
+ const convo = [
5219
+ { role: "system", content: systemInstruction },
5220
+ ...messages.map((m) => ({ role: m.role === "assistant" || m.role === "model" ? "assistant" : "user", content: m.content }))
5221
+ ];
5222
+ let finalContent = "";
5223
+ for (let round = 0; round < maxRounds; round++) {
5224
+ let turn;
5225
+ try {
5226
+ turn = await infer({ messages: convo, tools: loop.tools, temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
5227
+ }) });
5228
+ } catch (err) {
5229
+ const msg = String(err?.message || err);
5230
+ if (/tool/i.test(msg) && /40[04]|400|not support|invalid/i.test(msg)) {
5231
+ console.warn("[toolLoop] custom gateway rejected tools \u2014 degrading to plain chat:", msg.slice(0, 120));
5232
+ const plain = await infer({ messages: convo, tools: [], temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
5233
+ }) });
5234
+ finalContent = plain.content;
5235
+ break;
5236
+ }
5237
+ throw err;
5238
+ }
5239
+ const { content, toolCalls } = turn;
5240
+ if (toolCalls.length === 0) {
5241
+ finalContent = content;
5242
+ break;
5243
+ }
5244
+ if (content) finalContent = content;
5245
+ convo.push({ role: "assistant", content: content || null, tool_calls: toolCalls.map((t) => ({ id: t.id, type: "function", function: { name: t.name, arguments: t.arguments } })) });
5246
+ for (const call of toolCalls) {
5247
+ let parsedArgs = {};
5248
+ try {
5249
+ parsedArgs = JSON.parse(call.arguments || "{}");
5250
+ } catch {
5251
+ }
5252
+ loop.onToolStart?.(call.name, parsedArgs);
5253
+ let resultPayload;
5254
+ let isError = false;
5255
+ try {
5256
+ resultPayload = await loop.executor(call.name, parsedArgs);
5257
+ } catch (err) {
5258
+ isError = true;
5259
+ resultPayload = { error: err?.message || String(err) };
5260
+ loop.onToolError?.(call.name, err?.message || String(err));
5261
+ }
5262
+ const exec = { toolCallId: call.id, name: call.name, result: resultPayload, isError };
5263
+ loop.onToolResult?.(exec);
5264
+ convo.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify(resultPayload).slice(0, 12e3) });
5265
+ }
5266
+ if (round === maxRounds - 1) {
5267
+ const last = await infer({ messages: convo, tools: [], temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
5268
+ }) });
5269
+ finalContent = last.content;
5270
+ }
5271
+ }
5272
+ return finalContent;
5273
+ }
5196
5274
 
5197
5275
  exports.DEFAULT_ARTIFACT_STREAM_IDLE_MS = DEFAULT_ARTIFACT_STREAM_IDLE_MS;
5198
5276
  exports.DEFAULT_ARTIFACT_STREAM_TOTAL_MS = DEFAULT_ARTIFACT_STREAM_TOTAL_MS;