@burtson-labs/bandit-engine 2.0.71 → 2.0.73
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-W4HX45DE.mjs} +2 -2
- package/dist/{chunk-VKDU2OMI.mjs → chunk-E7GT3NR4.mjs} +2 -2
- package/dist/{chunk-CMBYMC3G.mjs → chunk-YBQRVTZF.mjs} +161 -37
- package/dist/chunk-YBQRVTZF.mjs.map +1 -0
- package/dist/index.js +160 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/management/management.js +160 -36
- 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-W4HX45DE.mjs.map} +0 -0
- /package/dist/{chunk-VKDU2OMI.mjs.map → chunk-E7GT3NR4.mjs.map} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
chat_default
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YBQRVTZF.mjs";
|
|
4
4
|
import {
|
|
5
5
|
chat_provider_default
|
|
6
6
|
} from "./chunk-SXLI47FV.mjs";
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
useGatewayHealth,
|
|
11
11
|
useGatewayMemory,
|
|
12
12
|
useGatewayModels
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-E7GT3NR4.mjs";
|
|
14
14
|
import "./chunk-U633CJBV.mjs";
|
|
15
15
|
import "./chunk-6ITUH375.mjs";
|
|
16
16
|
import "./chunk-DHYP4K5O.mjs";
|
|
@@ -23260,6 +23260,7 @@ ${protocol}`;
|
|
|
23260
23260
|
let latestDisplayMessage = "";
|
|
23261
23261
|
let sawToolBlock = false;
|
|
23262
23262
|
const nativeToolCalls = [];
|
|
23263
|
+
let workingTimer = null;
|
|
23263
23264
|
const stripThinking = (text) => {
|
|
23264
23265
|
let result = text.replace(/<think>[\s\S]*?<\/think>/g, "");
|
|
23265
23266
|
const openIdx = result.indexOf("<think>");
|
|
@@ -23267,6 +23268,28 @@ ${protocol}`;
|
|
|
23267
23268
|
return result.trimStart();
|
|
23268
23269
|
};
|
|
23269
23270
|
const stripToolBlocks = (text) => text.replace(/```(?:tool_code|TOOL_CODE)\s*\n[\s\S]*?\n```/gi, "").trim();
|
|
23271
|
+
let workingLabel = "Working on it";
|
|
23272
|
+
let workingPreamble = "";
|
|
23273
|
+
const stopWorking = () => {
|
|
23274
|
+
if (workingTimer) {
|
|
23275
|
+
clearInterval(workingTimer);
|
|
23276
|
+
workingTimer = null;
|
|
23277
|
+
}
|
|
23278
|
+
};
|
|
23279
|
+
const startWorking = (label = "Working on it") => {
|
|
23280
|
+
workingLabel = label.replace(/[.…]+\s*$/, "").trim() || "Working on it";
|
|
23281
|
+
workingPreamble = stripToolBlocks(stripThinking(fullMessage)).trim();
|
|
23282
|
+
if (workingTimer) return;
|
|
23283
|
+
let dots = 0;
|
|
23284
|
+
const render = () => {
|
|
23285
|
+
dots = (dots + 1) % 4;
|
|
23286
|
+
setStreamBuffer(
|
|
23287
|
+
`${workingPreamble}${workingPreamble ? "\n\n" : ""}_${workingLabel}${".".repeat(dots)}_`
|
|
23288
|
+
);
|
|
23289
|
+
};
|
|
23290
|
+
render();
|
|
23291
|
+
workingTimer = setInterval(render, 450);
|
|
23292
|
+
};
|
|
23270
23293
|
const flushNow = () => {
|
|
23271
23294
|
clearFlushTimer();
|
|
23272
23295
|
if (!sawToolBlock) {
|
|
@@ -23302,6 +23325,7 @@ ${protocol}`;
|
|
|
23302
23325
|
nativeToolCalls.push(...data.message.tool_calls);
|
|
23303
23326
|
sawToolBlock = true;
|
|
23304
23327
|
clearFlushTimer();
|
|
23328
|
+
startWorking();
|
|
23305
23329
|
}
|
|
23306
23330
|
if (data.message.content) {
|
|
23307
23331
|
fullMessage += data.message.content;
|
|
@@ -23313,6 +23337,7 @@ ${protocol}`;
|
|
|
23313
23337
|
if (/```(?:tool_code|TOOL_CODE)/.test(visibleMessage)) {
|
|
23314
23338
|
sawToolBlock = true;
|
|
23315
23339
|
clearFlushTimer();
|
|
23340
|
+
startWorking();
|
|
23316
23341
|
}
|
|
23317
23342
|
latestDisplayMessage = visibleMessage;
|
|
23318
23343
|
if (!sawToolBlock) {
|
|
@@ -23321,6 +23346,7 @@ ${protocol}`;
|
|
|
23321
23346
|
},
|
|
23322
23347
|
error: (err) => {
|
|
23323
23348
|
debugLogger.error("Stream error:", err);
|
|
23349
|
+
stopWorking();
|
|
23324
23350
|
overrideComponentStatus("Idle");
|
|
23325
23351
|
setIsSubmitting(false);
|
|
23326
23352
|
setIsStreaming(false);
|
|
@@ -23405,6 +23431,7 @@ ${fn}(${argStr})
|
|
|
23405
23431
|
if (functionName === "ask_user" || functionName === "ask-user") {
|
|
23406
23432
|
enhancedMessage = enhancedMessage.replace(match, "");
|
|
23407
23433
|
clearFlushTimer();
|
|
23434
|
+
stopWorking();
|
|
23408
23435
|
const askPreamble = stripToolBlocks(fullMessage).trim();
|
|
23409
23436
|
setStreamBuffer(askPreamble || "_Waiting for your answer\u2026_");
|
|
23410
23437
|
const questions = parseAskUserQuestions(
|
|
@@ -23427,11 +23454,8 @@ A: ${(answers[q.id] || "").trim() || "(no answer)"}`).join("\n\n") : "The user d
|
|
|
23427
23454
|
const placeholderToken = `<<TOOL_LOADING_${functionName}_${Math.random().toString(36).slice(2)}>>`;
|
|
23428
23455
|
enhancedMessage = enhancedMessage.replace(match, placeholderToken);
|
|
23429
23456
|
clearFlushTimer();
|
|
23430
|
-
const toolStatus = functionName === "web_search" || functionName === "web-search" ? "Searching the web
|
|
23431
|
-
|
|
23432
|
-
setStreamBuffer(toolPreamble ? `${toolPreamble}
|
|
23433
|
-
|
|
23434
|
-
_${toolStatus}_` : `_${toolStatus}_`);
|
|
23457
|
+
const toolStatus = functionName === "web_search" || functionName === "web-search" ? "Searching the web" : functionName === "web_fetch" || functionName === "web-fetch" ? "Reading the page" : functionName === "image_generation" || functionName === "image-generation" ? "Generating the image" : functionName === "create_file" || functionName === "create-file" ? "Creating your file" : "Working on it";
|
|
23458
|
+
startWorking(toolStatus);
|
|
23435
23459
|
telemetryEvent("tool_loop:tool_execute", { name: functionName, params: parsedParams });
|
|
23436
23460
|
const result = await executeMCPTool({
|
|
23437
23461
|
toolName: functionName,
|
|
@@ -23545,71 +23569,170 @@ _This link is temporary and expires in about ${mins} minutes._`;
|
|
|
23545
23569
|
try {
|
|
23546
23570
|
const toolResultsText = summarizableResults.map((r) => `## ${r.name}
|
|
23547
23571
|
${r.output}`).join("\n\n");
|
|
23548
|
-
const
|
|
23549
|
-
|
|
23572
|
+
const MAX_CHAIN_ROUNDS = 4;
|
|
23573
|
+
const enabledToolsForChain = getEnabledMCPToolsForAI();
|
|
23574
|
+
const convo = [
|
|
23575
|
+
{ role: "system", content: enhancedSystemPrompt },
|
|
23550
23576
|
...contextMessages,
|
|
23551
23577
|
{ role: "user", content: question },
|
|
23552
|
-
{ role: "assistant", content: stripToolBlocks(fullMessage) || "Let me
|
|
23578
|
+
{ role: "assistant", content: stripToolBlocks(fullMessage) || "Let me work on that." },
|
|
23553
23579
|
{
|
|
23554
23580
|
role: "user",
|
|
23555
|
-
content: `
|
|
23581
|
+
content: `Here are the results of the tool(s) so far:
|
|
23556
23582
|
|
|
23557
23583
|
${toolResultsText}
|
|
23558
23584
|
|
|
23559
|
-
|
|
23585
|
+
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.`
|
|
23560
23586
|
}
|
|
23561
23587
|
];
|
|
23562
|
-
const
|
|
23563
|
-
model: modelName,
|
|
23564
|
-
messages: summaryMessages,
|
|
23565
|
-
stream: true,
|
|
23566
|
-
options: { num_predict: tokenLimit + 250 }
|
|
23567
|
-
};
|
|
23568
|
-
clearFlushTimer();
|
|
23569
|
-
setStreamBuffer("");
|
|
23570
|
-
setIsThinking?.(true);
|
|
23571
|
-
const summaryText = await new Promise((resolve) => {
|
|
23588
|
+
const streamTurn = (req) => new Promise((resolve) => {
|
|
23572
23589
|
let acc = "";
|
|
23590
|
+
const native = [];
|
|
23573
23591
|
let settled = false;
|
|
23574
23592
|
let timer;
|
|
23575
|
-
const
|
|
23593
|
+
const finish = (value) => {
|
|
23576
23594
|
if (settled) return;
|
|
23577
23595
|
settled = true;
|
|
23578
23596
|
if (timer) clearTimeout(timer);
|
|
23579
23597
|
resolve(value);
|
|
23580
23598
|
};
|
|
23581
|
-
const
|
|
23599
|
+
const sub2 = provider.chat(req).subscribe({
|
|
23582
23600
|
next: (data) => {
|
|
23601
|
+
if (Array.isArray(data?.message?.tool_calls) && data.message.tool_calls.length) {
|
|
23602
|
+
native.push(...data.message.tool_calls);
|
|
23603
|
+
}
|
|
23583
23604
|
if (data?.message?.content) {
|
|
23584
23605
|
acc += data.message.content;
|
|
23585
23606
|
const visible = stripThinking(acc);
|
|
23586
23607
|
latestDisplayMessage = visible;
|
|
23587
23608
|
lastPartialRef.current.text = visible;
|
|
23588
|
-
if (visible)
|
|
23609
|
+
if (visible) {
|
|
23610
|
+
stopWorking();
|
|
23611
|
+
setIsThinking?.(false);
|
|
23612
|
+
}
|
|
23589
23613
|
setStreamBuffer(visible);
|
|
23590
23614
|
}
|
|
23591
23615
|
},
|
|
23592
|
-
error: (
|
|
23593
|
-
|
|
23594
|
-
error: summaryErr instanceof Error ? summaryErr.message : String(summaryErr)
|
|
23595
|
-
});
|
|
23596
|
-
done("");
|
|
23597
|
-
},
|
|
23598
|
-
complete: () => done(stripThinking(acc).trim())
|
|
23616
|
+
error: () => finish({ text: stripThinking(acc).trim(), native }),
|
|
23617
|
+
complete: () => finish({ text: stripThinking(acc).trim(), native })
|
|
23599
23618
|
});
|
|
23600
|
-
currentSubRef.current =
|
|
23619
|
+
currentSubRef.current = sub2;
|
|
23601
23620
|
timer = setTimeout(() => {
|
|
23602
|
-
debugLogger.warn("Summarization pass timed out; using inline tool output");
|
|
23603
23621
|
try {
|
|
23604
|
-
|
|
23622
|
+
sub2.unsubscribe();
|
|
23605
23623
|
} catch {
|
|
23606
23624
|
}
|
|
23607
|
-
|
|
23625
|
+
finish({ text: stripThinking(acc).trim(), native });
|
|
23608
23626
|
}, 3e4);
|
|
23609
23627
|
});
|
|
23628
|
+
const runChainedTool = async (fn, params) => {
|
|
23629
|
+
if (fn === "ask_user" || fn === "ask-user") {
|
|
23630
|
+
const qs = parseAskUserQuestions(params.questions ?? params);
|
|
23631
|
+
if (!qs.length) return "ask_user failed: it needs a questions array.";
|
|
23632
|
+
const ans = await useAskUserStore.getState().ask(qs);
|
|
23633
|
+
return ans ? "The user answered:\n\n" + qs.map((q) => `Q: ${q.question}
|
|
23634
|
+
A: ${(ans[q.id] || "").trim() || "(no answer)"}`).join("\n\n") : "The user dismissed the question(s). Proceed with your best judgment.";
|
|
23635
|
+
}
|
|
23636
|
+
const status = fn === "create_file" || fn === "create-file" ? "Creating your file" : fn === "web_search" || fn === "web-search" ? "Searching the web" : fn === "web_fetch" || fn === "web-fetch" ? "Reading the page" : fn === "image_generation" || fn === "image-generation" ? "Generating the image" : "Working on it";
|
|
23637
|
+
startWorking(status);
|
|
23638
|
+
const result = await executeMCPTool({ toolName: fn, parameters: params });
|
|
23639
|
+
if (!result.success) return `That step failed: ${result.error || "unknown error"}.`;
|
|
23640
|
+
if (fn === "create_file" || fn === "create-file") {
|
|
23641
|
+
const f = result.data ?? {};
|
|
23642
|
+
if (f.url) {
|
|
23643
|
+
const mins = f.expiresInMinutes ?? 60;
|
|
23644
|
+
const name = f.filename || "your file";
|
|
23645
|
+
inlineImageBlocks.push(`\u{1F4C4} **[${name}](${f.url})** \u2014 ready to download.
|
|
23646
|
+
|
|
23647
|
+
_This link is temporary and expires in about ${mins} minutes._`);
|
|
23648
|
+
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.`;
|
|
23649
|
+
}
|
|
23650
|
+
return "The file was created.";
|
|
23651
|
+
}
|
|
23652
|
+
if (fn === "image_generation" || fn === "image-generation") {
|
|
23653
|
+
const img = result.data ?? {};
|
|
23654
|
+
if (img.imageUrl) {
|
|
23655
|
+
inlineImageBlocks.push(``);
|
|
23656
|
+
return "Image generated and shown to the user.";
|
|
23657
|
+
}
|
|
23658
|
+
}
|
|
23659
|
+
if (typeof result.data === "string") return result.data.slice(0, 2e3);
|
|
23660
|
+
if (result.data) return JSON.stringify(result.data).slice(0, 1500);
|
|
23661
|
+
return "Done.";
|
|
23662
|
+
};
|
|
23663
|
+
clearFlushTimer();
|
|
23664
|
+
let finalText = "";
|
|
23665
|
+
let lastTurnText = "";
|
|
23666
|
+
for (let round = 0; round < MAX_CHAIN_ROUNDS; round++) {
|
|
23667
|
+
stopWorking();
|
|
23668
|
+
setStreamBuffer("");
|
|
23669
|
+
setIsThinking?.(true);
|
|
23670
|
+
const turnRequest = {
|
|
23671
|
+
model: modelName,
|
|
23672
|
+
messages: convo,
|
|
23673
|
+
stream: true,
|
|
23674
|
+
tools: enabledToolsForChain.length ? enabledToolsForChain : void 0,
|
|
23675
|
+
options: { num_predict: tokenLimit + 250 }
|
|
23676
|
+
};
|
|
23677
|
+
const { text: turnText, native: turnNative } = await streamTurn(turnRequest);
|
|
23678
|
+
setIsThinking?.(false);
|
|
23679
|
+
if (turnText.trim()) lastTurnText = turnText;
|
|
23680
|
+
let toolText = turnText;
|
|
23681
|
+
if (turnNative.length && !/```(?:tool_code|TOOL_CODE)/.test(toolText)) {
|
|
23682
|
+
for (const raw of turnNative) {
|
|
23683
|
+
const tc = raw;
|
|
23684
|
+
const fnName = tc.function?.name ?? tc.name;
|
|
23685
|
+
if (!fnName) continue;
|
|
23686
|
+
const a = tc.function?.arguments ?? tc.arguments ?? {};
|
|
23687
|
+
toolText += `
|
|
23688
|
+
|
|
23689
|
+
\`\`\`tool_code
|
|
23690
|
+
${fnName}(${typeof a === "string" ? a : JSON.stringify(a ?? {})})
|
|
23691
|
+
\`\`\``;
|
|
23692
|
+
}
|
|
23693
|
+
}
|
|
23694
|
+
const chainMatches = toolText.match(/```(?:tool_code|TOOL_CODE)\s*\n([^`]+)\n```/gi);
|
|
23695
|
+
if (!chainMatches || !chainMatches.length) {
|
|
23696
|
+
finalText = turnText;
|
|
23697
|
+
break;
|
|
23698
|
+
}
|
|
23699
|
+
const roundOut = [];
|
|
23700
|
+
for (const m of chainMatches) {
|
|
23701
|
+
const code = m.replace(/```(?:tool_code|TOOL_CODE)\s*\n|\n```/gi, "").trim();
|
|
23702
|
+
const fm = code.match(/^(\w+)\(\s*(.*?)\s*\)$/);
|
|
23703
|
+
if (!fm) continue;
|
|
23704
|
+
const [, fnName, rawParams] = fm;
|
|
23705
|
+
let parsed = {};
|
|
23706
|
+
const rp = rawParams.trim();
|
|
23707
|
+
if (rp) {
|
|
23708
|
+
try {
|
|
23709
|
+
parsed = JSON.parse(rp.startsWith("{") ? rp : `{${rp}}`);
|
|
23710
|
+
} catch {
|
|
23711
|
+
parsed = {};
|
|
23712
|
+
}
|
|
23713
|
+
}
|
|
23714
|
+
try {
|
|
23715
|
+
roundOut.push(`## ${fnName}
|
|
23716
|
+
${await runChainedTool(fnName, parsed)}`);
|
|
23717
|
+
} catch (e) {
|
|
23718
|
+
roundOut.push(`## ${fnName}
|
|
23719
|
+
That step failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
23720
|
+
}
|
|
23721
|
+
}
|
|
23722
|
+
convo.push({ role: "assistant", content: stripToolBlocks(turnText) || "(using a tool)" });
|
|
23723
|
+
convo.push({
|
|
23724
|
+
role: "user",
|
|
23725
|
+
content: `Tool results:
|
|
23726
|
+
|
|
23727
|
+
${roundOut.join("\n\n")}
|
|
23728
|
+
|
|
23729
|
+
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.`
|
|
23730
|
+
});
|
|
23731
|
+
}
|
|
23610
23732
|
setIsThinking?.(false);
|
|
23611
|
-
|
|
23612
|
-
|
|
23733
|
+
const answerText = finalText.trim() ? finalText : lastTurnText;
|
|
23734
|
+
if (answerText.trim() || inlineImageBlocks.length) {
|
|
23735
|
+
const cleanedSummary = answerText.replace(
|
|
23613
23736
|
/\n{1,}\s*(?:[*_#>\s]*)(?:sources?|references?|citations?|further reading)(?:\s*:)?\s*(?:[*_]*)\s*\n[\s\S]*$/i,
|
|
23614
23737
|
""
|
|
23615
23738
|
).trimEnd();
|
|
@@ -23635,6 +23758,7 @@ ${inlineImageBlocks.join("\n\n")}` : "");
|
|
|
23635
23758
|
}
|
|
23636
23759
|
}
|
|
23637
23760
|
}
|
|
23761
|
+
stopWorking();
|
|
23638
23762
|
overrideComponentStatus("Idle");
|
|
23639
23763
|
setIsSubmitting(false);
|
|
23640
23764
|
setPreviousQuestion(question);
|