@thanh01.pmt/curriculum-kit 1.4.31 → 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/index.cjs CHANGED
@@ -7937,6 +7937,8 @@ var LLMJudgeEngine = class {
7937
7937
  };
7938
7938
 
7939
7939
  // src/ai/chatToolLoop.ts
7940
+ init_streamRunner();
7941
+ init_errors();
7940
7942
  var PROVIDER_ENDPOINTS = {
7941
7943
  openrouter: "https://openrouter.ai/api/v1/chat/completions",
7942
7944
  deepseek: "https://api.deepseek.com/chat/completions",
@@ -8070,6 +8072,16 @@ async function runTurn(endpoint, model, apiKey, messages, tools, idleTimeoutMs,
8070
8072
  return { content: fullRaw, toolCalls };
8071
8073
  }
8072
8074
  async function streamCurriculumAIInferenceWithTools(messages, projectContext, options, loop, onChunk) {
8075
+ if (options.customToolInference) {
8076
+ return runToolLoopWithCustomInference(messages, projectContext, options, loop, onChunk);
8077
+ }
8078
+ if (resolveApiKey("CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE") === "1") {
8079
+ throw createAiInferenceError({
8080
+ errorCode: "ERR_CUSTOM_INFERENCE_REQUIRED",
8081
+ 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.",
8082
+ rawError: { mandate: "CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE", hasCustomToolInference: false }
8083
+ });
8084
+ }
8073
8085
  const route = resolveProviderRoute(options);
8074
8086
  const maxTokens = options.maxTokens ?? 32768;
8075
8087
  const maxRounds = loop.maxRounds ?? 4;
@@ -8134,6 +8146,74 @@ Guidelines:
8134
8146
  }
8135
8147
  return finalContent;
8136
8148
  }
8149
+ async function runToolLoopWithCustomInference(messages, projectContext, options, loop, onChunk) {
8150
+ const infer = options.customToolInference;
8151
+ const maxTokens = options.maxTokens ?? 32768;
8152
+ const maxRounds = loop.maxRounds ?? 4;
8153
+ const systemInstruction = `${options.systemPersona || "You are Curriculum OS Assistant."}
8154
+
8155
+ Project Context:
8156
+ ${projectContext}
8157
+
8158
+ Guidelines:
8159
+ 1. Answer precisely using the provided tools when they help (project status, deep research, production declaration, gate approval).
8160
+ 2. Keep Markdown formatting. Never invent tool results.`;
8161
+ const convo = [
8162
+ { role: "system", content: systemInstruction },
8163
+ ...messages.map((m) => ({ role: m.role === "assistant" || m.role === "model" ? "assistant" : "user", content: m.content }))
8164
+ ];
8165
+ let finalContent = "";
8166
+ for (let round = 0; round < maxRounds; round++) {
8167
+ let turn;
8168
+ try {
8169
+ turn = await infer({ messages: convo, tools: loop.tools, temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
8170
+ }) });
8171
+ } catch (err) {
8172
+ const msg = String(err?.message || err);
8173
+ if (/tool/i.test(msg) && /40[04]|400|not support|invalid/i.test(msg)) {
8174
+ console.warn("[toolLoop] custom gateway rejected tools \u2014 degrading to plain chat:", msg.slice(0, 120));
8175
+ const plain = await infer({ messages: convo, tools: [], temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
8176
+ }) });
8177
+ finalContent = plain.content;
8178
+ break;
8179
+ }
8180
+ throw err;
8181
+ }
8182
+ const { content, toolCalls } = turn;
8183
+ if (toolCalls.length === 0) {
8184
+ finalContent = content;
8185
+ break;
8186
+ }
8187
+ if (content) finalContent = content;
8188
+ convo.push({ role: "assistant", content: content || null, tool_calls: toolCalls.map((t) => ({ id: t.id, type: "function", function: { name: t.name, arguments: t.arguments } })) });
8189
+ for (const call of toolCalls) {
8190
+ let parsedArgs = {};
8191
+ try {
8192
+ parsedArgs = JSON.parse(call.arguments || "{}");
8193
+ } catch {
8194
+ }
8195
+ loop.onToolStart?.(call.name, parsedArgs);
8196
+ let resultPayload;
8197
+ let isError = false;
8198
+ try {
8199
+ resultPayload = await loop.executor(call.name, parsedArgs);
8200
+ } catch (err) {
8201
+ isError = true;
8202
+ resultPayload = { error: err?.message || String(err) };
8203
+ loop.onToolError?.(call.name, err?.message || String(err));
8204
+ }
8205
+ const exec = { toolCallId: call.id, name: call.name, result: resultPayload, isError };
8206
+ loop.onToolResult?.(exec);
8207
+ convo.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify(resultPayload).slice(0, 12e3) });
8208
+ }
8209
+ if (round === maxRounds - 1) {
8210
+ const last = await infer({ messages: convo, tools: [], temperature: options.temperature ?? 0.3, maxTokens, onChunk: onChunk ?? (() => {
8211
+ }) });
8212
+ finalContent = last.content;
8213
+ }
8214
+ }
8215
+ return finalContent;
8216
+ }
8137
8217
 
8138
8218
  // src/pipeline/markdownSerializers.ts
8139
8219
  function serializeLessonToMarkdown(lesson) {