@burtson-labs/bandit-engine 2.0.61 → 2.0.63

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.
@@ -12681,85 +12681,8 @@ var init_ai_response_action_bar = __esm({
12681
12681
  }
12682
12682
  });
12683
12683
 
12684
- // src/services/branding/brandingService.ts
12685
- var BrandingService, brandingService, brandingService_default;
12686
- var init_brandingService = __esm({
12687
- "src/services/branding/brandingService.ts"() {
12688
- "use strict";
12689
- init_indexedDBService();
12690
- init_debugLogger();
12691
- BrandingService = class {
12692
- DB_NAME = "banditConfig";
12693
- DB_VERSION = 1;
12694
- STORE_NAME = "config";
12695
- STORE_CONFIGS = [{ name: "config", keyPath: "id" }];
12696
- async getBranding() {
12697
- try {
12698
- const data = await indexedDBService_default.get(
12699
- this.DB_NAME,
12700
- this.DB_VERSION,
12701
- this.STORE_NAME,
12702
- "main",
12703
- this.STORE_CONFIGS
12704
- );
12705
- if (data?.branding && (data.branding.logoBase64 || data.branding.hasTransparentLogo !== void 0 || data.branding.brandingText)) {
12706
- return {
12707
- logoBase64: data.branding.logoBase64,
12708
- hasTransparentLogo: data.branding.hasTransparentLogo,
12709
- brandingText: data.branding.brandingText
12710
- };
12711
- }
12712
- return null;
12713
- } catch (error) {
12714
- throw error;
12715
- }
12716
- }
12717
- async setBrandingFromConfig(config) {
12718
- try {
12719
- const existing = await indexedDBService_default.get(
12720
- this.DB_NAME,
12721
- this.DB_VERSION,
12722
- this.STORE_NAME,
12723
- "main",
12724
- this.STORE_CONFIGS
12725
- ) || { id: "main" };
12726
- if (existing.branding?.userSaved) {
12727
- debugLogger.debug("\u{1F6E1}\uFE0F BrandingService: User branding detected, blocking CDN config override");
12728
- return;
12729
- }
12730
- const hasUserBranding = existing.branding && (existing.branding.logoBase64 || existing.branding.brandingText || existing.branding.theme || existing.branding.hasTransparentLogo !== void 0);
12731
- if (hasUserBranding) {
12732
- debugLogger.debug("\u{1F6E1}\uFE0F BrandingService: Detected user branding data, blocking CDN config override");
12733
- return;
12734
- }
12735
- debugLogger.debug("\u{1F527} BrandingService: No user branding detected, applying CDN config");
12736
- const branding = config.branding || {};
12737
- const updated = {
12738
- ...existing,
12739
- branding: {
12740
- ...existing.branding,
12741
- ...branding
12742
- }
12743
- };
12744
- await indexedDBService_default.put(
12745
- this.DB_NAME,
12746
- this.DB_VERSION,
12747
- this.STORE_NAME,
12748
- updated,
12749
- this.STORE_CONFIGS
12750
- );
12751
- } catch (error) {
12752
- throw error;
12753
- }
12754
- }
12755
- };
12756
- brandingService = new BrandingService();
12757
- brandingService_default = brandingService;
12758
- }
12759
- });
12760
-
12761
12684
  // src/modals/chat-modal/ai-response-text-field.tsx
12762
- var import_react14, import_styles2, import_react_markdown, import_remark_gfm, import_rehype_raw, import_rehype_sanitize2, import_material8, import_jsx_runtime9, brainIcon, avatarFilenames, banditHead3, resolveAvatar2, normalizeTables, isNonEmptyString, toDateSafe, toNumberArray, MarkdownCodeBlock, AIResponseTextField, ai_response_text_field_default;
12685
+ var import_react14, import_styles2, import_react_markdown, import_remark_gfm, import_rehype_raw, import_rehype_sanitize2, import_material8, import_jsx_runtime9, brainIcon, normalizeTables, isNonEmptyString, toDateSafe, toNumberArray, MarkdownCodeBlock, AIResponseTextField, ai_response_text_field_default;
12763
12686
  var init_ai_response_text_field = __esm({
12764
12687
  "src/modals/chat-modal/ai-response-text-field.tsx"() {
12765
12688
  "use strict";
@@ -12774,33 +12697,12 @@ var init_ai_response_text_field = __esm({
12774
12697
  import_rehype_sanitize2 = __toESM(require("rehype-sanitize"));
12775
12698
  init_debugLogger();
12776
12699
  import_material8 = require("@mui/material");
12777
- init_modelStore();
12778
12700
  init_lowlight();
12779
12701
  init_markdownRendering();
12780
12702
  init_lucide_icons();
12781
12703
  init_ai_response_action_bar();
12782
- init_brandingService();
12783
12704
  import_jsx_runtime9 = require("react/jsx-runtime");
12784
12705
  brainIcon = "https://cdn.burtson.ai/images/brain-icon.png";
12785
- avatarFilenames = {
12786
- "Bandit-Core": "core-avatar.png",
12787
- "Bandit-Muse": "muse-avatar.png",
12788
- "Bandit-Logic": "logic-avatar.png",
12789
- "Bandit-D1VA": "d1va-avatar.png",
12790
- "Bandit-Exec": "exec-avatar.png",
12791
- "default": "bandit-head.png"
12792
- };
12793
- banditHead3 = `https://cdn.burtson.ai/images/bandit-head.png`;
12794
- resolveAvatar2 = (selectedModel) => {
12795
- const model = useModelStore.getState().availableModels.find(
12796
- (m) => m.name === selectedModel
12797
- );
12798
- if (model?.avatarBase64) {
12799
- return model.avatarBase64;
12800
- }
12801
- const avatarFilename = avatarFilenames[selectedModel] || avatarFilenames["default"];
12802
- return `https://cdn.burtson.ai/avatars/${avatarFilename}`;
12803
- };
12804
12706
  normalizeTables = (markdown2) => {
12805
12707
  const lines = markdown2.split("\n");
12806
12708
  const output = [];
@@ -13146,15 +13048,6 @@ var init_ai_response_text_field = __esm({
13146
13048
  const timeout3 = setTimeout(() => setShowMemoryUpdated(false), 3e3);
13147
13049
  return () => clearTimeout(timeout3);
13148
13050
  }, [memoryUpdated]);
13149
- const selectedModel = useModelStore((state) => state.selectedModel);
13150
- const [userAvatar, setUserAvatar] = (0, import_react14.useState)(banditHead3);
13151
- (0, import_react14.useEffect)(() => {
13152
- const fetchBranding = async () => {
13153
- const branding = await brandingService_default.getBranding();
13154
- setUserAvatar(branding?.logoBase64 || banditHead3);
13155
- };
13156
- fetchBranding();
13157
- }, []);
13158
13051
  const theme = (0, import_styles2.useTheme)();
13159
13052
  const chatResponse = theme.palette.chat?.response;
13160
13053
  const sanitizeMarkdown = (raw) => {
@@ -13523,283 +13416,108 @@ ${sourcesMarkdownList.join("\n")}`;
13523
13416
  alignSelf: "stretch",
13524
13417
  display: "flex",
13525
13418
  flexDirection: "column",
13526
- bgcolor: chatResponse.containerBackground,
13527
- color: chatResponse.aiText || "#fff",
13528
- p: isMobile ? 1 : 2,
13529
- borderRadius: "4px",
13530
- userSelect: "text",
13531
- border: "1px solid " + (chatResponse.aiBorder || "#ccc"),
13532
- boxShadow: "0 0 6px rgba(0,0,0,0.3)"
13419
+ color: chatResponse.aiText || theme.palette.text.primary,
13420
+ px: isMobile ? 0.5 : 2,
13421
+ py: 1,
13422
+ userSelect: "text"
13533
13423
  },
13534
13424
  children: [
13535
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
13536
- import_material8.Box,
13537
- {
13538
- sx: {
13539
- display: "flex",
13540
- flexDirection: "column",
13541
- alignItems: {
13542
- xs: "flex-start",
13543
- sm: "flex-end"
13425
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Box, { sx: { display: "flex", justifyContent: "flex-end", mb: 2.5 }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_material8.Box, { sx: { maxWidth: { xs: "100%", sm: "85%" }, minWidth: 0 }, children: [
13426
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13427
+ import_material8.Box,
13428
+ {
13429
+ sx: {
13430
+ bgcolor: chatResponse.userBubble || (0, import_styles2.alpha)(theme.palette.common.white, 0.07),
13431
+ borderRadius: "18px",
13432
+ px: 2,
13433
+ py: 1.25,
13434
+ wordBreak: "break-word",
13435
+ whiteSpace: "pre-wrap",
13436
+ overflowWrap: "break-word"
13544
13437
  },
13545
- gap: 2,
13546
- mb: 2,
13547
- justifyContent: "flex-end"
13548
- },
13549
- children: [
13550
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
13551
- import_material8.Box,
13438
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13439
+ import_material8.Typography,
13552
13440
  {
13553
13441
  sx: {
13554
- display: "flex",
13555
- flexDirection: "column",
13556
- alignItems: "center"
13442
+ color: theme.palette.text.primary,
13443
+ lineHeight: 1.5,
13444
+ wordBreak: "break-word",
13445
+ whiteSpace: "pre-wrap"
13557
13446
  },
13558
- children: [
13559
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13560
- import_material8.Avatar,
13561
- {
13562
- alt: "You",
13563
- src: userAvatar,
13564
- sx: {
13565
- display: { xs: "none", sm: "flex" },
13566
- width: { sm: 72 },
13567
- height: { sm: 72 },
13568
- bgcolor: chatResponse.userAvatarBackground || (theme.palette.mode === "dark" ? "transparent" : "#eee"),
13569
- color: "#fff",
13570
- fontWeight: "bold",
13571
- fontSize: { sm: "1.1rem" },
13572
- border: "2px solid #a78bfa",
13573
- boxShadow: "0 0 8px rgba(167, 139, 250, 0.3)",
13574
- transform: "scaleX(1)"
13575
- }
13576
- }
13577
- ),
13578
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13579
- import_material8.Typography,
13580
- {
13581
- variant: "caption",
13582
- sx: { color: chatResponse.modelLabel || "#888", mt: 1, fontStyle: "italic" },
13583
- children: "You said"
13584
- }
13585
- )
13586
- ]
13447
+ children: question
13587
13448
  }
13588
- ),
13589
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_material8.Box, { sx: { flex: 1 }, children: [
13590
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13591
- import_material8.Box,
13592
- {
13593
- sx: {
13594
- display: "inline-block",
13595
- textAlign: "left",
13596
- bgcolor: chatResponse.userBubble || "#1f1f1f",
13597
- borderRadius: "4px",
13598
- px: isMobile ? 1 : 2,
13599
- py: 1.5,
13600
- width: isMobile ? "100%" : "fit-content",
13601
- maxWidth: "100%",
13602
- border: "1px solid " + (chatResponse.aiBorder || "#444"),
13603
- wordBreak: "break-word",
13604
- whiteSpace: "pre-wrap",
13605
- overflowWrap: "break-word",
13606
- mt: { xs: 0.5, sm: 0.25 }
13607
- },
13608
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13609
- import_material8.Typography,
13610
- {
13611
- sx: {
13612
- color: chatResponse.userText || "#6C9AC5",
13613
- fontStyle: "italic",
13614
- wordBreak: "break-word",
13615
- whiteSpace: "pre-wrap"
13616
- },
13617
- children: question
13618
- }
13619
- )
13620
- }
13621
- ),
13622
- images && images.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Box, { sx: { display: "flex", gap: 1, mt: 1, flexWrap: "wrap" }, children: images.map((img, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13623
- import_material8.Avatar,
13624
- {
13625
- src: img,
13626
- variant: "rounded",
13627
- onClick: () => setOpenImage(img),
13628
- sx: {
13629
- width: 64,
13630
- height: 64,
13631
- borderRadius: 2,
13632
- cursor: "pointer",
13633
- "&:hover": { boxShadow: `0 0 0 2px ${theme.palette.primary.main}` }
13634
- }
13635
- },
13636
- i
13637
- )) })
13638
- ] })
13639
- ]
13640
- }
13641
- ),
13642
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Box, { sx: { borderBottom: `1px solid ${theme.palette.divider}`, my: 2 } }),
13643
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
13644
- import_material8.Box,
13645
- {
13646
- sx: {
13647
- display: "flex",
13648
- flexDirection: "column",
13649
- alignItems: {
13650
- xs: "center",
13651
- sm: "flex-start"
13652
- },
13653
- gap: 2,
13654
- mb: 2
13449
+ )
13450
+ }
13451
+ ),
13452
+ images && images.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Box, { sx: { display: "flex", gap: 1, mt: 1, flexWrap: "wrap", justifyContent: "flex-end" }, children: images.map((img, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13453
+ import_material8.Avatar,
13454
+ {
13455
+ src: img,
13456
+ variant: "rounded",
13457
+ onClick: () => setOpenImage(img),
13458
+ sx: {
13459
+ width: 64,
13460
+ height: 64,
13461
+ borderRadius: 2,
13462
+ cursor: "pointer",
13463
+ "&:hover": { boxShadow: `0 0 0 2px ${theme.palette.primary.main}` }
13464
+ }
13655
13465
  },
13656
- children: [
13657
- typeof response === "string" && response.trim() !== "" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
13658
- import_material8.Box,
13659
- {
13660
- sx: {
13661
- display: "flex",
13662
- flexDirection: "column",
13663
- alignItems: "center",
13664
- mr: 2,
13665
- position: "relative"
13666
- },
13667
- children: [
13668
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13669
- import_material8.Avatar,
13670
- {
13671
- src: resolveAvatar2(selectedModel),
13672
- alt: selectedModel,
13673
- sx: {
13674
- display: { xs: "none", sm: "flex" },
13675
- width: 72,
13676
- height: 72,
13677
- border: "1px solid #888",
13678
- boxShadow: "0 0 6px rgba(136, 136, 136, 0.4)",
13679
- filter: "brightness(1.6)"
13680
- }
13681
- }
13682
- ),
13683
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Box, { sx: { display: { xs: "none", sm: "block" } }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
13684
- import_material8.Typography,
13685
- {
13686
- variant: "caption",
13687
- sx: { color: chatResponse.modelLabel || "#888", mt: 1, fontStyle: "italic" },
13688
- children: [
13689
- selectedModel,
13690
- " says"
13691
- ]
13692
- }
13693
- ) })
13694
- ]
13695
- }
13696
- ),
13697
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13698
- import_material8.Box,
13699
- {
13700
- sx: {
13701
- display: { xs: "flex", sm: "none" },
13702
- justifyContent: "right",
13703
- width: "100%",
13704
- mt: -1,
13705
- mb: 1
13706
- },
13707
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
13708
- import_material8.Typography,
13709
- {
13710
- variant: "caption",
13711
- sx: { fontStyle: "italic", color: chatResponse.modelLabel || "#888" },
13712
- children: [
13713
- selectedModel,
13714
- " says"
13715
- ]
13716
- }
13717
- )
13718
- }
13719
- ),
13720
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_material8.Box, { sx: { position: "relative", width: "100%" }, children: [
13721
- cancelled && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13722
- import_material8.Box,
13723
- {
13724
- sx: {
13725
- position: "absolute",
13726
- top: -24,
13727
- left: 0,
13728
- display: "flex",
13729
- alignItems: "center",
13730
- gap: 1,
13731
- pl: 1,
13732
- zIndex: 1
13733
- },
13734
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Typography, { variant: "caption", sx: { fontStyle: "italic", opacity: 0.85 }, children: "Cancelled by you" })
13735
- }
13736
- ),
13737
- showMemoryUpdated && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
13738
- import_material8.Box,
13739
- {
13740
- sx: {
13741
- position: "absolute",
13742
- top: -24,
13743
- right: 0,
13744
- display: "flex",
13745
- alignItems: "center",
13746
- gap: 1,
13747
- pr: 1,
13748
- animation: "fadeOut 0.3s ease-in 2.7s forwards",
13749
- zIndex: 1
13750
- },
13751
- children: [
13752
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13753
- "img",
13754
- {
13755
- src: brainIcon,
13756
- alt: "Memory",
13757
- style: { width: 18, height: 18 }
13758
- }
13759
- ),
13760
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13761
- import_material8.Typography,
13762
- {
13763
- variant: "caption",
13764
- sx: { color: chatResponse.memoryText || "#2e7d32", fontStyle: "italic" },
13765
- children: "Bandit added to memory"
13766
- }
13767
- )
13768
- ]
13769
- }
13770
- ),
13466
+ i
13467
+ )) })
13468
+ ] }) }),
13469
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_material8.Box, { sx: { position: "relative", width: "100%", maxWidth: { xs: "100%", sm: "768px" } }, children: [
13470
+ cancelled && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13471
+ import_material8.Box,
13472
+ {
13473
+ sx: {
13474
+ position: "absolute",
13475
+ top: -22,
13476
+ left: 0,
13477
+ display: "flex",
13478
+ alignItems: "center",
13479
+ gap: 1,
13480
+ zIndex: 1
13481
+ },
13482
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Typography, { variant: "caption", sx: { fontStyle: "italic", opacity: 0.85 }, children: "Cancelled by you" })
13483
+ }
13484
+ ),
13485
+ showMemoryUpdated && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
13486
+ import_material8.Box,
13487
+ {
13488
+ sx: {
13489
+ position: "absolute",
13490
+ top: -22,
13491
+ right: 0,
13492
+ display: "flex",
13493
+ alignItems: "center",
13494
+ gap: 1,
13495
+ animation: "fadeOut 0.3s ease-in 2.7s forwards",
13496
+ zIndex: 1
13497
+ },
13498
+ children: [
13499
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: brainIcon, alt: "Memory", style: { width: 16, height: 16 } }),
13771
13500
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13772
- import_material8.Box,
13501
+ import_material8.Typography,
13773
13502
  {
13774
- sx: {
13775
- bgcolor: chatResponse.aiBubble ?? "#2f2f2f",
13776
- borderRadius: "4px",
13777
- px: isMobile ? 1 : 1.5,
13778
- // Reduced padding on mobile
13779
- py: 1.25,
13780
- width: "100%",
13781
- maxWidth: isMobile ? "100%" : "768px",
13782
- // Full width on mobile
13783
- border: "1px solid " + (chatResponse.aiBorder || "#ccc"),
13784
- wordBreak: "break-word",
13785
- alignSelf: "flex-start",
13786
- mt: { xs: 0.5, sm: 0.25 }
13787
- },
13788
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Box, { sx: { width: "100%", maxWidth: "100%" }, children: typeof response === "string" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13789
- import_react_markdown.default,
13790
- {
13791
- remarkPlugins: [import_remark_gfm.default],
13792
- rehypePlugins: [import_rehype_raw.default, [import_rehype_sanitize2.default, markdownSanitizeSchema]],
13793
- components,
13794
- children: enrichedMarkdown ?? sanitizeMarkdown(response)
13795
- }
13796
- ) : import_react14.default.isValidElement(response) ? response : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Typography, { color: "error", children: "\u26A0\uFE0F Invalid AI response" }) })
13503
+ variant: "caption",
13504
+ sx: { color: chatResponse.memoryText || "#2e7d32", fontStyle: "italic" },
13505
+ children: "Bandit added to memory"
13797
13506
  }
13798
13507
  )
13799
- ] })
13800
- ]
13801
- }
13802
- ),
13508
+ ]
13509
+ }
13510
+ ),
13511
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Box, { sx: { width: "100%", maxWidth: "100%" }, children: typeof response === "string" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13512
+ import_react_markdown.default,
13513
+ {
13514
+ remarkPlugins: [import_remark_gfm.default],
13515
+ rehypePlugins: [import_rehype_raw.default, [import_rehype_sanitize2.default, markdownSanitizeSchema]],
13516
+ components,
13517
+ children: enrichedMarkdown ?? sanitizeMarkdown(response)
13518
+ }
13519
+ ) : import_react14.default.isValidElement(response) ? response : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Typography, { color: "error", children: "\u26A0\uFE0F Invalid AI response" }) })
13520
+ ] }),
13803
13521
  !!(responseText || typeof response === "string" && response) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ai_response_action_bar_default, { text: responseText || response }),
13804
13522
  displaySourceFiles && displaySourceFiles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Box, { sx: { mt: 1.5, display: "flex", gap: 2, flexWrap: "wrap", justifyContent: "flex-start" }, children: displaySourceFiles.map((doc, idx) => {
13805
13523
  debugLogger.debug("Rendering DocumentCard in AI response", {
@@ -16821,6 +16539,83 @@ var init_useNotificationService = __esm({
16821
16539
  }
16822
16540
  });
16823
16541
 
16542
+ // src/services/branding/brandingService.ts
16543
+ var BrandingService, brandingService, brandingService_default;
16544
+ var init_brandingService = __esm({
16545
+ "src/services/branding/brandingService.ts"() {
16546
+ "use strict";
16547
+ init_indexedDBService();
16548
+ init_debugLogger();
16549
+ BrandingService = class {
16550
+ DB_NAME = "banditConfig";
16551
+ DB_VERSION = 1;
16552
+ STORE_NAME = "config";
16553
+ STORE_CONFIGS = [{ name: "config", keyPath: "id" }];
16554
+ async getBranding() {
16555
+ try {
16556
+ const data = await indexedDBService_default.get(
16557
+ this.DB_NAME,
16558
+ this.DB_VERSION,
16559
+ this.STORE_NAME,
16560
+ "main",
16561
+ this.STORE_CONFIGS
16562
+ );
16563
+ if (data?.branding && (data.branding.logoBase64 || data.branding.hasTransparentLogo !== void 0 || data.branding.brandingText)) {
16564
+ return {
16565
+ logoBase64: data.branding.logoBase64,
16566
+ hasTransparentLogo: data.branding.hasTransparentLogo,
16567
+ brandingText: data.branding.brandingText
16568
+ };
16569
+ }
16570
+ return null;
16571
+ } catch (error) {
16572
+ throw error;
16573
+ }
16574
+ }
16575
+ async setBrandingFromConfig(config) {
16576
+ try {
16577
+ const existing = await indexedDBService_default.get(
16578
+ this.DB_NAME,
16579
+ this.DB_VERSION,
16580
+ this.STORE_NAME,
16581
+ "main",
16582
+ this.STORE_CONFIGS
16583
+ ) || { id: "main" };
16584
+ if (existing.branding?.userSaved) {
16585
+ debugLogger.debug("\u{1F6E1}\uFE0F BrandingService: User branding detected, blocking CDN config override");
16586
+ return;
16587
+ }
16588
+ const hasUserBranding = existing.branding && (existing.branding.logoBase64 || existing.branding.brandingText || existing.branding.theme || existing.branding.hasTransparentLogo !== void 0);
16589
+ if (hasUserBranding) {
16590
+ debugLogger.debug("\u{1F6E1}\uFE0F BrandingService: Detected user branding data, blocking CDN config override");
16591
+ return;
16592
+ }
16593
+ debugLogger.debug("\u{1F527} BrandingService: No user branding detected, applying CDN config");
16594
+ const branding = config.branding || {};
16595
+ const updated = {
16596
+ ...existing,
16597
+ branding: {
16598
+ ...existing.branding,
16599
+ ...branding
16600
+ }
16601
+ };
16602
+ await indexedDBService_default.put(
16603
+ this.DB_NAME,
16604
+ this.DB_VERSION,
16605
+ this.STORE_NAME,
16606
+ updated,
16607
+ this.STORE_CONFIGS
16608
+ );
16609
+ } catch (error) {
16610
+ throw error;
16611
+ }
16612
+ }
16613
+ };
16614
+ brandingService = new BrandingService();
16615
+ brandingService_default = brandingService;
16616
+ }
16617
+ });
16618
+
16824
16619
  // src/theme/banditTheme.ts
16825
16620
  var import_styles5, commonOptions, banditDarkTheme, banditLightTheme;
16826
16621
  var init_banditTheme = __esm({
@@ -23216,6 +23011,7 @@ ${protocol}`;
23216
23011
  let fullMessage = "";
23217
23012
  let latestDisplayMessage = "";
23218
23013
  let sawToolBlock = false;
23014
+ const nativeToolCalls = [];
23219
23015
  const stripThinking = (text) => {
23220
23016
  let result = text.replace(/<think>[\s\S]*?<\/think>/g, "");
23221
23017
  const openIdx = result.indexOf("<think>");
@@ -23254,6 +23050,11 @@ ${protocol}`;
23254
23050
  const sub = stream.subscribe({
23255
23051
  next: (data) => {
23256
23052
  if (!data?.message?.content && !data?.message?.tool_calls) return;
23053
+ if (Array.isArray(data.message.tool_calls) && data.message.tool_calls.length > 0) {
23054
+ nativeToolCalls.push(...data.message.tool_calls);
23055
+ sawToolBlock = true;
23056
+ clearFlushTimer();
23057
+ }
23257
23058
  if (data.message.content) {
23258
23059
  fullMessage += data.message.content;
23259
23060
  telemetryEvent("tool_loop:llm_chunk", { chunk: data.message.content });
@@ -23302,6 +23103,20 @@ ${protocol}`;
23302
23103
  if (!sawToolBlock) {
23303
23104
  flushNow();
23304
23105
  }
23106
+ if (nativeToolCalls.length > 0 && !/```(?:tool_code|TOOL_CODE)/.test(fullMessage)) {
23107
+ for (const raw of nativeToolCalls) {
23108
+ const tc = raw;
23109
+ const fn = tc.function?.name ?? tc.name;
23110
+ if (!fn) continue;
23111
+ const rawArgs = tc.function?.arguments ?? tc.arguments ?? {};
23112
+ const argStr = typeof rawArgs === "string" ? rawArgs : JSON.stringify(rawArgs ?? {});
23113
+ fullMessage += `
23114
+
23115
+ \`\`\`tool_code
23116
+ ${fn}(${argStr})
23117
+ \`\`\``;
23118
+ }
23119
+ }
23305
23120
  const toolCallMatches = fullMessage.match(/```(?:tool_code|TOOL_CODE)\s*\n([^`]+)\n```/gi);
23306
23121
  let enhancedMessage = fullMessage;
23307
23122
  const summarizableResults = [];
@@ -27055,7 +26870,7 @@ var init_enhanced_mobile_conversations_modal = __esm({
27055
26870
  });
27056
26871
 
27057
26872
  // src/chat/chat-app-bar.tsx
27058
- var import_material42, import_react53, import_material43, import_react_router_dom2, import_shallow2, import_jsx_runtime42, CDN_BASE2, banditHead5, modelAvatars3, ChatAppBar, chat_app_bar_default;
26873
+ var import_material42, import_react53, import_material43, import_react_router_dom2, import_shallow2, import_jsx_runtime42, CDN_BASE2, banditHead4, modelAvatars3, ChatAppBar, chat_app_bar_default;
27059
26874
  var init_chat_app_bar = __esm({
27060
26875
  "src/chat/chat-app-bar.tsx"() {
27061
26876
  "use strict";
@@ -27079,7 +26894,7 @@ var init_chat_app_bar = __esm({
27079
26894
  import_shallow2 = require("zustand/shallow");
27080
26895
  import_jsx_runtime42 = require("react/jsx-runtime");
27081
26896
  CDN_BASE2 = "https://cdn.burtson.ai/";
27082
- banditHead5 = `${CDN_BASE2}/images/bandit-head.png`;
26897
+ banditHead4 = `${CDN_BASE2}/images/bandit-head.png`;
27083
26898
  modelAvatars3 = {
27084
26899
  "Bandit-Core": `${CDN_BASE2}/avatars/core-avatar.png`,
27085
26900
  "Bandit-Muse": `${CDN_BASE2}/avatars/muse-avatar.png`,
@@ -27245,16 +27060,18 @@ var init_chat_app_bar = __esm({
27245
27060
  };
27246
27061
  const selectedModel = useModelStore((s) => s.selectedModel);
27247
27062
  const currentModel = useModelStore((s) => s.availableModels.find((m) => m.name === selectedModel));
27248
- const currentAvatar = currentModel?.avatarBase64 || modelAvatars3[selectedModel] || banditHead5;
27063
+ const currentAvatar = currentModel?.avatarBase64 || modelAvatars3[selectedModel] || banditHead4;
27249
27064
  const engines = useEngineStore((s) => s.engines);
27250
27065
  const selectedEngine = useEngineStore((s) => s.selectedEngine);
27251
27066
  const effectiveEngineId = selectedEngine || usePackageSettingsStore.getState().settings?.defaultModel || "bandit-core";
27252
- const currentEngine = engines.find((e) => e.id === effectiveEngineId);
27253
- const engineLabel = currentEngine?.displayName?.replace(/^Bandit /, "") || "Engine";
27067
+ const currentEngine = engines.find((e) => e.id === effectiveEngineId) || engines.find((e) => effectiveEngineId.startsWith(e.id + ":"));
27068
+ const resolvedEngineId = currentEngine?.id ?? effectiveEngineId;
27069
+ const cleanEngineName = (name) => (name || "").replace(/\s*\([^)]*\)\s*$/, "").trim();
27070
+ const engineDisplay = cleanEngineName(currentEngine?.displayName) || "Engine";
27254
27071
  (0, import_react53.useEffect)(() => {
27255
27072
  useEngineStore.getState().fetchEngines();
27256
27073
  }, []);
27257
- const pendingModelAvatar = useModelStore.getState().availableModels.find((m) => m.name === pendingModel)?.avatarBase64 || modelAvatars3[pendingModel || ""] || banditHead5;
27074
+ const pendingModelAvatar = useModelStore.getState().availableModels.find((m) => m.name === pendingModel)?.avatarBase64 || modelAvatars3[pendingModel || ""] || banditHead4;
27258
27075
  const resolvedHomeUrl = preferences.homeUrl?.trim() || packageSettings?.homeUrl?.trim() || "";
27259
27076
  const homeTooltip = (() => {
27260
27077
  if (!resolvedHomeUrl) return "Home";
@@ -27566,16 +27383,13 @@ var init_chat_app_bar = __esm({
27566
27383
  )
27567
27384
  }
27568
27385
  ) }),
27569
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Tooltip, { title: `Engine: ${currentEngine?.displayName ?? effectiveEngineId}`, arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
27386
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Tooltip, { title: `Engine \xB7 ${engineDisplay}`, arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
27570
27387
  import_material43.IconButton,
27571
27388
  {
27572
27389
  onClick: (e) => setEngineAnchorEl(e.currentTarget),
27573
27390
  sx: pillButtonStyles,
27574
- "aria-label": `Change base model (engine). Currently ${effectiveEngineId}`,
27575
- children: [
27576
- currentEngine?.cloud ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(CloudDoneIcon, { fontSize: "small" }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(CloudOffIcon, { fontSize: "small" }),
27577
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Typography, { variant: "caption", sx: { ml: 0.75, fontWeight: 600, whiteSpace: "nowrap" }, children: engineLabel })
27578
- ]
27391
+ "aria-label": `Change base model (engine). Currently ${engineDisplay}`,
27392
+ children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AutoAwesomeIcon, { fontSize: "small" })
27579
27393
  }
27580
27394
  ) }),
27581
27395
  /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
@@ -27599,7 +27413,7 @@ var init_chat_app_bar = __esm({
27599
27413
  return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
27600
27414
  import_material43.MenuItem,
27601
27415
  {
27602
- selected: engine.id === effectiveEngineId,
27416
+ selected: engine.id === resolvedEngineId,
27603
27417
  disabled: !engine.available,
27604
27418
  onClick: () => {
27605
27419
  useEngineStore.getState().setSelectedEngine(engine.id);
@@ -27617,8 +27431,8 @@ var init_chat_app_bar = __esm({
27617
27431
  },
27618
27432
  children: [
27619
27433
  /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_material43.Box, { sx: { display: "flex", alignItems: "center", gap: 1, width: "100%" }, children: [
27620
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Typography, { variant: "body2", sx: { fontWeight: 600, flex: 1 }, children: engine.displayName }),
27621
- engine.id === effectiveEngineId && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Box, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: theme.palette.primary.main } })
27434
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Typography, { variant: "body2", sx: { fontWeight: 600, flex: 1 }, children: cleanEngineName(engine.displayName) }),
27435
+ engine.id === resolvedEngineId && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_material43.Box, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: theme.palette.primary.main } })
27622
27436
  ] }),
27623
27437
  /* @__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" }),
27624
27438
  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)(
@@ -27730,7 +27544,7 @@ var init_chat_app_bar = __esm({
27730
27544
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
27731
27545
  import_material42.Avatar,
27732
27546
  {
27733
- src: model.avatarBase64 || modelAvatars3[model.name] || banditHead5,
27547
+ src: model.avatarBase64 || modelAvatars3[model.name] || banditHead4,
27734
27548
  alt: model.name,
27735
27549
  sx: {
27736
27550
  width: 28,
@@ -31958,7 +31772,7 @@ init_lucide_icons();
31958
31772
  var import_jsx_runtime16 = require("react/jsx-runtime");
31959
31773
  var FULL_SCREEN_THRESHOLD = 100;
31960
31774
  var CDN_BASE = "https://cdn.burtson.ai/";
31961
- var banditHead4 = `${CDN_BASE}/images/bandit-head.png`;
31775
+ var banditHead3 = `${CDN_BASE}/images/bandit-head.png`;
31962
31776
  var modelAvatars2 = {
31963
31777
  "Bandit-Core": `${CDN_BASE}/avatars/core-avatar.png`,
31964
31778
  "Bandit-Muse": `${CDN_BASE}/avatars/muse-avatar.png`,
@@ -32048,7 +31862,7 @@ var ChatModal = ({
32048
31862
  const provider = useAIProviderStore((state) => state.provider);
32049
31863
  const notificationService2 = useNotificationService();
32050
31864
  const currentModel = availableModels.find((m) => m.name === selectedModel);
32051
- const currentAvatar = currentModel?.avatarBase64 || modelAvatars2[selectedModel] || banditHead4;
31865
+ const currentAvatar = currentModel?.avatarBase64 || modelAvatars2[selectedModel] || banditHead3;
32052
31866
  const removeImage = (index) => {
32053
31867
  setPastedImages((prev) => prev.filter((_, i) => i !== index));
32054
31868
  };
@@ -32368,7 +32182,7 @@ var ChatModal = ({
32368
32182
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
32369
32183
  import_material17.Avatar,
32370
32184
  {
32371
- src: model.avatarBase64 || modelAvatars2[model.name] || banditHead4,
32185
+ src: model.avatarBase64 || modelAvatars2[model.name] || banditHead3,
32372
32186
  alt: model.name,
32373
32187
  sx: {
32374
32188
  width: 28,
@@ -42083,7 +41897,7 @@ var Management = () => {
42083
41897
  const isMobile = (0, import_useMediaQuery2.default)("(max-width:900px)");
42084
41898
  const [sidebarOpen, setSidebarOpen] = (0, import_react57.useState)(false);
42085
41899
  const getOptimalFabLogo = async () => {
42086
- const banditHead7 = "https://cdn.burtson.ai/images/bandit-head.png";
41900
+ const banditHead6 = "https://cdn.burtson.ai/images/bandit-head.png";
42087
41901
  try {
42088
41902
  const subdomain = window.location.hostname.split(".")[0];
42089
41903
  const faviconUrl = `https://cdn.burtson.ai/favicons/${subdomain}/favicon.png`;
@@ -42100,10 +41914,10 @@ var Management = () => {
42100
41914
  if (branding?.logoBase64) {
42101
41915
  return branding.logoBase64;
42102
41916
  }
42103
- return banditHead7;
41917
+ return banditHead6;
42104
41918
  } catch (error) {
42105
41919
  debugLogger.error("Failed to get optimal FAB logo", { error });
42106
- return banditHead7;
41920
+ return banditHead6;
42107
41921
  }
42108
41922
  };
42109
41923
  const {
@@ -42122,8 +41936,8 @@ var Management = () => {
42122
41936
  setHasTransparentLogo
42123
41937
  } = useModelStore();
42124
41938
  const [modalOpen, setModalOpen] = (0, import_react57.useState)(false);
42125
- const banditHead6 = "https://cdn.burtson.ai/images/bandit-head.png";
42126
- const [fabLogo, setFabLogo] = (0, import_react57.useState)(banditHead6);
41939
+ const banditHead5 = "https://cdn.burtson.ai/images/bandit-head.png";
41940
+ const [fabLogo, setFabLogo] = (0, import_react57.useState)(banditHead5);
42127
41941
  const [tabIndex, setTabIndex] = (0, import_react57.useState)(4);
42128
41942
  const [logoFile, setLogoFile] = (0, import_react57.useState)(null);
42129
41943
  const [logoBase64, setLogoBase64] = (0, import_react57.useState)(null);