@burtson-labs/bandit-engine 2.0.71 → 2.0.72
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/{chat-2QWK6OUO.mjs → chat-GLBQOPNT.mjs} +2 -2
- package/dist/{chunk-VKDU2OMI.mjs → chunk-7ZHLQXHL.mjs} +2 -2
- package/dist/{chunk-CMBYMC3G.mjs → chunk-LDL4X6CB.mjs} +126 -31
- package/dist/chunk-LDL4X6CB.mjs.map +1 -0
- package/dist/index.js +125 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/management/management.js +125 -30
- package/dist/management/management.js.map +1 -1
- package/dist/management/management.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-CMBYMC3G.mjs.map +0 -1
- /package/dist/{chat-2QWK6OUO.mjs.map → chat-GLBQOPNT.mjs.map} +0 -0
- /package/dist/{chunk-VKDU2OMI.mjs.map → chunk-7ZHLQXHL.mjs.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -21306,41 +21306,38 @@ _This link is temporary and expires in about ${mins} minutes._`;
|
|
|
21306
21306
|
try {
|
|
21307
21307
|
const toolResultsText = summarizableResults.map((r) => `## ${r.name}
|
|
21308
21308
|
${r.output}`).join("\n\n");
|
|
21309
|
-
const
|
|
21310
|
-
|
|
21309
|
+
const MAX_CHAIN_ROUNDS = 4;
|
|
21310
|
+
const enabledToolsForChain = getEnabledMCPToolsForAI();
|
|
21311
|
+
const convo = [
|
|
21312
|
+
{ role: "system", content: enhancedSystemPrompt },
|
|
21311
21313
|
...contextMessages,
|
|
21312
21314
|
{ role: "user", content: question },
|
|
21313
|
-
{ role: "assistant", content: stripToolBlocks(fullMessage) || "Let me
|
|
21315
|
+
{ role: "assistant", content: stripToolBlocks(fullMessage) || "Let me work on that." },
|
|
21314
21316
|
{
|
|
21315
21317
|
role: "user",
|
|
21316
|
-
content: `
|
|
21318
|
+
content: `Here are the results of the tool(s) so far:
|
|
21317
21319
|
|
|
21318
21320
|
${toolResultsText}
|
|
21319
21321
|
|
|
21320
|
-
|
|
21322
|
+
Use them to fully complete my original request. If you still need to take an action I asked for (for example, actually create a file I want to download), call the appropriate tool now with a \`\`\`tool_code\`\`\` block. Otherwise give your final answer. Do NOT add a "Sources"/"References"/"Citations" list \u2014 one is appended automatically.`
|
|
21321
21323
|
}
|
|
21322
21324
|
];
|
|
21323
|
-
const
|
|
21324
|
-
model: modelName,
|
|
21325
|
-
messages: summaryMessages,
|
|
21326
|
-
stream: true,
|
|
21327
|
-
options: { num_predict: tokenLimit + 250 }
|
|
21328
|
-
};
|
|
21329
|
-
clearFlushTimer();
|
|
21330
|
-
setStreamBuffer("");
|
|
21331
|
-
setIsThinking?.(true);
|
|
21332
|
-
const summaryText = await new Promise((resolve) => {
|
|
21325
|
+
const streamTurn = (req) => new Promise((resolve) => {
|
|
21333
21326
|
let acc = "";
|
|
21327
|
+
const native = [];
|
|
21334
21328
|
let settled = false;
|
|
21335
21329
|
let timer;
|
|
21336
|
-
const
|
|
21330
|
+
const finish = (value) => {
|
|
21337
21331
|
if (settled) return;
|
|
21338
21332
|
settled = true;
|
|
21339
21333
|
if (timer) clearTimeout(timer);
|
|
21340
21334
|
resolve(value);
|
|
21341
21335
|
};
|
|
21342
|
-
const
|
|
21336
|
+
const sub2 = provider.chat(req).subscribe({
|
|
21343
21337
|
next: (data) => {
|
|
21338
|
+
if (Array.isArray(data?.message?.tool_calls) && data.message.tool_calls.length) {
|
|
21339
|
+
native.push(...data.message.tool_calls);
|
|
21340
|
+
}
|
|
21344
21341
|
if (data?.message?.content) {
|
|
21345
21342
|
acc += data.message.content;
|
|
21346
21343
|
const visible = stripThinking(acc);
|
|
@@ -21350,27 +21347,125 @@ Using these results together with your own knowledge, answer my original questio
|
|
|
21350
21347
|
setStreamBuffer(visible);
|
|
21351
21348
|
}
|
|
21352
21349
|
},
|
|
21353
|
-
error: (
|
|
21354
|
-
|
|
21355
|
-
error: summaryErr instanceof Error ? summaryErr.message : String(summaryErr)
|
|
21356
|
-
});
|
|
21357
|
-
done("");
|
|
21358
|
-
},
|
|
21359
|
-
complete: () => done(stripThinking(acc).trim())
|
|
21350
|
+
error: () => finish({ text: stripThinking(acc).trim(), native }),
|
|
21351
|
+
complete: () => finish({ text: stripThinking(acc).trim(), native })
|
|
21360
21352
|
});
|
|
21361
|
-
currentSubRef.current =
|
|
21353
|
+
currentSubRef.current = sub2;
|
|
21362
21354
|
timer = setTimeout(() => {
|
|
21363
|
-
debugLogger.warn("Summarization pass timed out; using inline tool output");
|
|
21364
21355
|
try {
|
|
21365
|
-
|
|
21356
|
+
sub2.unsubscribe();
|
|
21366
21357
|
} catch {
|
|
21367
21358
|
}
|
|
21368
|
-
|
|
21359
|
+
finish({ text: stripThinking(acc).trim(), native });
|
|
21369
21360
|
}, 3e4);
|
|
21370
21361
|
});
|
|
21362
|
+
const runChainedTool = async (fn, params) => {
|
|
21363
|
+
if (fn === "ask_user" || fn === "ask-user") {
|
|
21364
|
+
const qs = parseAskUserQuestions(params.questions ?? params);
|
|
21365
|
+
if (!qs.length) return "ask_user failed: it needs a questions array.";
|
|
21366
|
+
const ans = await useAskUserStore.getState().ask(qs);
|
|
21367
|
+
return ans ? "The user answered:\n\n" + qs.map((q) => `Q: ${q.question}
|
|
21368
|
+
A: ${(ans[q.id] || "").trim() || "(no answer)"}`).join("\n\n") : "The user dismissed the question(s). Proceed with your best judgment.";
|
|
21369
|
+
}
|
|
21370
|
+
const status = fn === "create_file" || fn === "create-file" ? "Creating the file\u2026" : fn === "web_search" || fn === "web-search" ? "Searching the web\u2026" : fn === "web_fetch" || fn === "web-fetch" ? "Reading the page\u2026" : fn === "image_generation" || fn === "image-generation" ? "Generating the image\u2026" : "Working on it\u2026";
|
|
21371
|
+
setStreamBuffer(`_${status}_`);
|
|
21372
|
+
const result = await executeMCPTool({ toolName: fn, parameters: params });
|
|
21373
|
+
if (!result.success) return `That step failed: ${result.error || "unknown error"}.`;
|
|
21374
|
+
if (fn === "create_file" || fn === "create-file") {
|
|
21375
|
+
const f = result.data ?? {};
|
|
21376
|
+
if (f.url) {
|
|
21377
|
+
const mins = f.expiresInMinutes ?? 60;
|
|
21378
|
+
const name = f.filename || "your file";
|
|
21379
|
+
inlineImageBlocks.push(`\u{1F4C4} **[${name}](${f.url})** \u2014 ready to download.
|
|
21380
|
+
|
|
21381
|
+
_This link is temporary and expires in about ${mins} minutes._`);
|
|
21382
|
+
return `File created and its download link is now shown to the user. Briefly confirm it's ready and that it expires in ~${mins} minutes.`;
|
|
21383
|
+
}
|
|
21384
|
+
return "The file was created.";
|
|
21385
|
+
}
|
|
21386
|
+
if (fn === "image_generation" || fn === "image-generation") {
|
|
21387
|
+
const img = result.data ?? {};
|
|
21388
|
+
if (img.imageUrl) {
|
|
21389
|
+
inlineImageBlocks.push(``);
|
|
21390
|
+
return "Image generated and shown to the user.";
|
|
21391
|
+
}
|
|
21392
|
+
}
|
|
21393
|
+
if (typeof result.data === "string") return result.data.slice(0, 2e3);
|
|
21394
|
+
if (result.data) return JSON.stringify(result.data).slice(0, 1500);
|
|
21395
|
+
return "Done.";
|
|
21396
|
+
};
|
|
21397
|
+
clearFlushTimer();
|
|
21398
|
+
let finalText = "";
|
|
21399
|
+
let lastTurnText = "";
|
|
21400
|
+
for (let round = 0; round < MAX_CHAIN_ROUNDS; round++) {
|
|
21401
|
+
setStreamBuffer("");
|
|
21402
|
+
setIsThinking?.(true);
|
|
21403
|
+
const turnRequest = {
|
|
21404
|
+
model: modelName,
|
|
21405
|
+
messages: convo,
|
|
21406
|
+
stream: true,
|
|
21407
|
+
tools: enabledToolsForChain.length ? enabledToolsForChain : void 0,
|
|
21408
|
+
options: { num_predict: tokenLimit + 250 }
|
|
21409
|
+
};
|
|
21410
|
+
const { text: turnText, native: turnNative } = await streamTurn(turnRequest);
|
|
21411
|
+
setIsThinking?.(false);
|
|
21412
|
+
if (turnText.trim()) lastTurnText = turnText;
|
|
21413
|
+
let toolText = turnText;
|
|
21414
|
+
if (turnNative.length && !/```(?:tool_code|TOOL_CODE)/.test(toolText)) {
|
|
21415
|
+
for (const raw of turnNative) {
|
|
21416
|
+
const tc = raw;
|
|
21417
|
+
const fnName = tc.function?.name ?? tc.name;
|
|
21418
|
+
if (!fnName) continue;
|
|
21419
|
+
const a = tc.function?.arguments ?? tc.arguments ?? {};
|
|
21420
|
+
toolText += `
|
|
21421
|
+
|
|
21422
|
+
\`\`\`tool_code
|
|
21423
|
+
${fnName}(${typeof a === "string" ? a : JSON.stringify(a ?? {})})
|
|
21424
|
+
\`\`\``;
|
|
21425
|
+
}
|
|
21426
|
+
}
|
|
21427
|
+
const chainMatches = toolText.match(/```(?:tool_code|TOOL_CODE)\s*\n([^`]+)\n```/gi);
|
|
21428
|
+
if (!chainMatches || !chainMatches.length) {
|
|
21429
|
+
finalText = turnText;
|
|
21430
|
+
break;
|
|
21431
|
+
}
|
|
21432
|
+
const roundOut = [];
|
|
21433
|
+
for (const m of chainMatches) {
|
|
21434
|
+
const code = m.replace(/```(?:tool_code|TOOL_CODE)\s*\n|\n```/gi, "").trim();
|
|
21435
|
+
const fm = code.match(/^(\w+)\(\s*(.*?)\s*\)$/);
|
|
21436
|
+
if (!fm) continue;
|
|
21437
|
+
const [, fnName, rawParams] = fm;
|
|
21438
|
+
let parsed = {};
|
|
21439
|
+
const rp = rawParams.trim();
|
|
21440
|
+
if (rp) {
|
|
21441
|
+
try {
|
|
21442
|
+
parsed = JSON.parse(rp.startsWith("{") ? rp : `{${rp}}`);
|
|
21443
|
+
} catch {
|
|
21444
|
+
parsed = {};
|
|
21445
|
+
}
|
|
21446
|
+
}
|
|
21447
|
+
try {
|
|
21448
|
+
roundOut.push(`## ${fnName}
|
|
21449
|
+
${await runChainedTool(fnName, parsed)}`);
|
|
21450
|
+
} catch (e) {
|
|
21451
|
+
roundOut.push(`## ${fnName}
|
|
21452
|
+
That step failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
21453
|
+
}
|
|
21454
|
+
}
|
|
21455
|
+
convo.push({ role: "assistant", content: stripToolBlocks(turnText) || "(using a tool)" });
|
|
21456
|
+
convo.push({
|
|
21457
|
+
role: "user",
|
|
21458
|
+
content: `Tool results:
|
|
21459
|
+
|
|
21460
|
+
${roundOut.join("\n\n")}
|
|
21461
|
+
|
|
21462
|
+
Now give your final answer to my original request, or call another tool if you still genuinely need to. Do NOT add a "Sources" list.`
|
|
21463
|
+
});
|
|
21464
|
+
}
|
|
21371
21465
|
setIsThinking?.(false);
|
|
21372
|
-
|
|
21373
|
-
|
|
21466
|
+
const answerText = finalText.trim() ? finalText : lastTurnText;
|
|
21467
|
+
if (answerText.trim() || inlineImageBlocks.length) {
|
|
21468
|
+
const cleanedSummary = answerText.replace(
|
|
21374
21469
|
/\n{1,}\s*(?:[*_#>\s]*)(?:sources?|references?|citations?|further reading)(?:\s*:)?\s*(?:[*_]*)\s*\n[\s\S]*$/i,
|
|
21375
21470
|
""
|
|
21376
21471
|
).trimEnd();
|