@burtson-labs/bandit-engine 2.0.60 → 2.0.62

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.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  chat_default
3
- } from "./chunk-MFDMM5MS.mjs";
3
+ } from "./chunk-Y4NDNAAR.mjs";
4
4
  import {
5
5
  chat_provider_default
6
6
  } from "./chunk-D55E6ZDV.mjs";
@@ -10,7 +10,7 @@ import {
10
10
  useGatewayHealth,
11
11
  useGatewayMemory,
12
12
  useGatewayModels
13
- } from "./chunk-3AWAL2YH.mjs";
13
+ } from "./chunk-O7JGT7HR.mjs";
14
14
  import "./chunk-SRCCNBHF.mjs";
15
15
  import "./chunk-VTC6AIWY.mjs";
16
16
  import "./chunk-6QTTNYF2.mjs";
@@ -21674,6 +21674,64 @@ var init_telemetry = __esm({
21674
21674
  }
21675
21675
  });
21676
21676
 
21677
+ // src/store/engineStore.ts
21678
+ var import_zustand15, STORAGE_KEY2, readStored, useEngineStore;
21679
+ var init_engineStore = __esm({
21680
+ "src/store/engineStore.ts"() {
21681
+ "use strict";
21682
+ import_zustand15 = require("zustand");
21683
+ init_packageSettingsStore();
21684
+ init_authenticationService();
21685
+ init_debugLogger();
21686
+ STORAGE_KEY2 = "bandit.selectedEngine";
21687
+ readStored = () => {
21688
+ try {
21689
+ return typeof window !== "undefined" ? window.localStorage.getItem(STORAGE_KEY2) : null;
21690
+ } catch {
21691
+ return null;
21692
+ }
21693
+ };
21694
+ useEngineStore = (0, import_zustand15.create)((set, get) => ({
21695
+ selectedEngine: readStored(),
21696
+ engines: [],
21697
+ loaded: false,
21698
+ setSelectedEngine: (id) => {
21699
+ set({ selectedEngine: id });
21700
+ try {
21701
+ window.localStorage.setItem(STORAGE_KEY2, id);
21702
+ } catch {
21703
+ }
21704
+ },
21705
+ getSelectedEngine: () => get().selectedEngine || usePackageSettingsStore.getState().settings?.defaultModel || "bandit-core",
21706
+ fetchEngines: async () => {
21707
+ const settings = usePackageSettingsStore.getState().settings;
21708
+ const base = settings?.gatewayApiUrl?.replace(/\/$/, "") ?? "";
21709
+ if (!base || settings?.playgroundMode || base.toLowerCase().startsWith("playground://")) {
21710
+ set({ loaded: true });
21711
+ return;
21712
+ }
21713
+ try {
21714
+ const headers = { "Content-Type": "application/json" };
21715
+ const token = authenticationService.getToken();
21716
+ if (token) headers["Authorization"] = `Bearer ${token}`;
21717
+ const res = await fetch(`${base}/models`, { headers });
21718
+ const data = await res.json();
21719
+ if (res.ok && Array.isArray(data?.models)) {
21720
+ set({ engines: data.models, loaded: true });
21721
+ } else {
21722
+ set({ loaded: true });
21723
+ }
21724
+ } catch (error) {
21725
+ debugLogger.error("Failed to fetch engines", {
21726
+ error: error instanceof Error ? error.message : String(error)
21727
+ });
21728
+ set({ loaded: true });
21729
+ }
21730
+ }
21731
+ }));
21732
+ }
21733
+ });
21734
+
21677
21735
  // src/chat/hooks/useMemoryEnhancer.tsx
21678
21736
  var import_rxjs23, MEMORY_LIMIT, MIN_MEMORY_WORDS, MERGE_THRESHOLD, REJECT_ECHO_THRESHOLD, REJECT_DUPLICATE_THRESHOLD, CONTEXTUAL_DIVERGENCE_THRESHOLD, normalizeText, isStructurallyDuplicate, isAboutBandit, hasEngagementValue, isMemoryTooShortOrGeneric, isPersonalText, mergeMemory, isVoiceShifted, sanitizeMemory, sanitizeMemoryText, shouldAcceptMemory, isContextuallyDivergent, useMemoryEnhancer;
21679
21737
  var init_useMemoryEnhancer = __esm({
@@ -22416,12 +22474,12 @@ var init_useAIProvider = __esm({
22416
22474
  init_knowledgeStore();
22417
22475
  init_aiProviderStore();
22418
22476
  init_telemetry();
22477
+ init_engineStore();
22419
22478
  init_conversationStore();
22420
22479
  init_useMemoryEnhancer();
22421
22480
  init_useVectorStore();
22422
22481
  init_embeddingService();
22423
22482
  init_useMoodEngine();
22424
- init_packageSettingsStore();
22425
22483
  init_prompts();
22426
22484
  init_preferencesStore();
22427
22485
  init_mcp();
@@ -22785,7 +22843,7 @@ var init_useAIProvider = __esm({
22785
22843
  question: pendingQuestion,
22786
22844
  images: pendingImages
22787
22845
  });
22788
- const modelName = usePackageSettingsStore.getState().settings?.defaultModel || "bandit-core:4b-it-qat";
22846
+ const modelName = useEngineStore.getState().getSelectedEngine();
22789
22847
  const CONFIG = modelConfigs[modelName] ?? modelConfigs["bandit-core:4b-it-qat"];
22790
22848
  const base64Images = imageList.map((img) => img.split(",")[1]);
22791
22849
  const latestEntries = history.slice(-CONFIG.historyMessages);
@@ -23158,6 +23216,7 @@ ${protocol}`;
23158
23216
  let fullMessage = "";
23159
23217
  let latestDisplayMessage = "";
23160
23218
  let sawToolBlock = false;
23219
+ const nativeToolCalls = [];
23161
23220
  const stripThinking = (text) => {
23162
23221
  let result = text.replace(/<think>[\s\S]*?<\/think>/g, "");
23163
23222
  const openIdx = result.indexOf("<think>");
@@ -23196,6 +23255,11 @@ ${protocol}`;
23196
23255
  const sub = stream.subscribe({
23197
23256
  next: (data) => {
23198
23257
  if (!data?.message?.content && !data?.message?.tool_calls) return;
23258
+ if (Array.isArray(data.message.tool_calls) && data.message.tool_calls.length > 0) {
23259
+ nativeToolCalls.push(...data.message.tool_calls);
23260
+ sawToolBlock = true;
23261
+ clearFlushTimer();
23262
+ }
23199
23263
  if (data.message.content) {
23200
23264
  fullMessage += data.message.content;
23201
23265
  telemetryEvent("tool_loop:llm_chunk", { chunk: data.message.content });
@@ -23244,6 +23308,20 @@ ${protocol}`;
23244
23308
  if (!sawToolBlock) {
23245
23309
  flushNow();
23246
23310
  }
23311
+ if (nativeToolCalls.length > 0 && !/```(?:tool_code|TOOL_CODE)/.test(fullMessage)) {
23312
+ for (const raw of nativeToolCalls) {
23313
+ const tc = raw;
23314
+ const fn = tc.function?.name ?? tc.name;
23315
+ if (!fn) continue;
23316
+ const rawArgs = tc.function?.arguments ?? tc.arguments ?? {};
23317
+ const argStr = typeof rawArgs === "string" ? rawArgs : JSON.stringify(rawArgs ?? {});
23318
+ fullMessage += `
23319
+
23320
+ \`\`\`tool_code
23321
+ ${fn}(${argStr})
23322
+ \`\`\``;
23323
+ }
23324
+ }
23247
23325
  const toolCallMatches = fullMessage.match(/```(?:tool_code|TOOL_CODE)\s*\n([^`]+)\n```/gi);
23248
23326
  let enhancedMessage = fullMessage;
23249
23327
  const summarizableResults = [];
@@ -27017,6 +27095,7 @@ var init_chat_app_bar = __esm({
27017
27095
  init_packageSettingsStore();
27018
27096
  init_useFeatures();
27019
27097
  init_conversationSyncStore();
27098
+ init_engineStore();
27020
27099
  import_shallow2 = require("zustand/shallow");
27021
27100
  import_jsx_runtime42 = require("react/jsx-runtime");
27022
27101
  CDN_BASE2 = "https://cdn.burtson.ai/";
@@ -27066,6 +27145,7 @@ var init_chat_app_bar = __esm({
27066
27145
  menuText
27067
27146
  } = theme.palette.chat.appBar;
27068
27147
  const [modelAnchorEl, setModelAnchorEl] = (0, import_react53.useState)(null);
27148
+ const [engineAnchorEl, setEngineAnchorEl] = (0, import_react53.useState)(null);
27069
27149
  const [voiceAnchorEl, setVoiceAnchorEl] = (0, import_react53.useState)(null);
27070
27150
  const [modalOpen, setModalOpen] = (0, import_react53.useState)(false);
27071
27151
  const [confirmModelChangeOpen, setConfirmModelChangeOpen] = (0, import_react53.useState)(false);
@@ -27186,6 +27266,16 @@ var init_chat_app_bar = __esm({
27186
27266
  const selectedModel = useModelStore((s) => s.selectedModel);
27187
27267
  const currentModel = useModelStore((s) => s.availableModels.find((m) => m.name === selectedModel));
27188
27268
  const currentAvatar = currentModel?.avatarBase64 || modelAvatars3[selectedModel] || banditHead5;
27269
+ const engines = useEngineStore((s) => s.engines);
27270
+ const selectedEngine = useEngineStore((s) => s.selectedEngine);
27271
+ const effectiveEngineId = selectedEngine || usePackageSettingsStore.getState().settings?.defaultModel || "bandit-core";
27272
+ const currentEngine = engines.find((e) => e.id === effectiveEngineId) || engines.find((e) => effectiveEngineId.startsWith(e.id + ":"));
27273
+ const resolvedEngineId = currentEngine?.id ?? effectiveEngineId;
27274
+ const cleanEngineName = (name) => (name || "").replace(/\s*\([^)]*\)\s*$/, "").trim();
27275
+ const engineDisplay = cleanEngineName(currentEngine?.displayName) || "Engine";
27276
+ (0, import_react53.useEffect)(() => {
27277
+ useEngineStore.getState().fetchEngines();
27278
+ }, []);
27189
27279
  const pendingModelAvatar = useModelStore.getState().availableModels.find((m) => m.name === pendingModel)?.avatarBase64 || modelAvatars3[pendingModel || ""] || banditHead5;
27190
27280
  const resolvedHomeUrl = preferences.homeUrl?.trim() || packageSettings?.homeUrl?.trim() || "";
27191
27281
  const homeTooltip = (() => {
@@ -27498,6 +27588,81 @@ var init_chat_app_bar = __esm({
27498
27588
  )
27499
27589
  }
27500
27590
  ) }),
27591
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Tooltip, { title: `Engine \xB7 ${engineDisplay}`, arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
27592
+ import_material43.IconButton,
27593
+ {
27594
+ onClick: (e) => setEngineAnchorEl(e.currentTarget),
27595
+ sx: pillButtonStyles,
27596
+ "aria-label": `Change base model (engine). Currently ${engineDisplay}`,
27597
+ children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(PsychologyIcon, { fontSize: "small" })
27598
+ }
27599
+ ) }),
27600
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
27601
+ import_material43.Menu,
27602
+ {
27603
+ anchorEl: engineAnchorEl,
27604
+ open: Boolean(engineAnchorEl),
27605
+ onClose: () => setEngineAnchorEl(null),
27606
+ transformOrigin: { horizontal: "right", vertical: "top" },
27607
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
27608
+ children: [
27609
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Typography, { variant: "overline", sx: { px: 2, color: theme.palette.text.secondary }, children: "Engine \xB7 base model" }),
27610
+ engines.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.MenuItem, { disabled: true, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Typography, { variant: "body2", children: "No engines available" }) }),
27611
+ engines.map((engine) => {
27612
+ const badges = [
27613
+ engine.vision && "vision",
27614
+ engine.tools && "tools",
27615
+ engine.thinking && "thinking",
27616
+ engine.cloud && "cloud"
27617
+ ].filter(Boolean);
27618
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
27619
+ import_material43.MenuItem,
27620
+ {
27621
+ selected: engine.id === resolvedEngineId,
27622
+ disabled: !engine.available,
27623
+ onClick: () => {
27624
+ useEngineStore.getState().setSelectedEngine(engine.id);
27625
+ setEngineAnchorEl(null);
27626
+ },
27627
+ sx: {
27628
+ display: "flex",
27629
+ flexDirection: "column",
27630
+ alignItems: "flex-start",
27631
+ gap: 0.5,
27632
+ py: 1,
27633
+ px: 2,
27634
+ maxWidth: 360,
27635
+ whiteSpace: "normal"
27636
+ },
27637
+ children: [
27638
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_material43.Box, { sx: { display: "flex", alignItems: "center", gap: 1, width: "100%" }, children: [
27639
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Typography, { variant: "body2", sx: { fontWeight: 600, flex: 1 }, children: cleanEngineName(engine.displayName) }),
27640
+ engine.id === resolvedEngineId && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Box, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: theme.palette.primary.main } })
27641
+ ] }),
27642
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Typography, { variant: "caption", sx: { color: theme.palette.text.secondary }, children: engine.available ? engine.description : engine.unavailableReason || "Unavailable" }),
27643
+ badges.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Box, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap", mt: 0.25 }, children: badges.map((b) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
27644
+ import_material43.Box,
27645
+ {
27646
+ sx: {
27647
+ fontSize: "0.65rem",
27648
+ px: 0.75,
27649
+ py: 0.1,
27650
+ borderRadius: 1,
27651
+ bgcolor: theme.palette.primary.main + "22",
27652
+ color: theme.palette.primary.main
27653
+ },
27654
+ children: b
27655
+ },
27656
+ b
27657
+ )) })
27658
+ ]
27659
+ },
27660
+ engine.id
27661
+ );
27662
+ })
27663
+ ]
27664
+ }
27665
+ ),
27501
27666
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
27502
27667
  import_material43.Menu,
27503
27668
  {