@burtson-labs/bandit-engine 2.0.44 → 2.0.49

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.
Files changed (54) hide show
  1. package/README.md +7 -5
  2. package/dist/{aiProviderStore-UQI33C5E.mjs → aiProviderStore-3N3VE6D4.mjs} +2 -2
  3. package/dist/chat-647M6BRG.mjs +15 -0
  4. package/dist/chat-provider.js +45 -10
  5. package/dist/chat-provider.js.map +1 -1
  6. package/dist/chat-provider.mjs +6 -6
  7. package/dist/{chunk-UXE67LR7.mjs → chunk-6WZUQHZT.mjs} +11 -7
  8. package/dist/chunk-6WZUQHZT.mjs.map +1 -0
  9. package/dist/{chunk-QV4ELNLP.mjs → chunk-7HXARU5R.mjs} +58 -19
  10. package/dist/chunk-7HXARU5R.mjs.map +1 -0
  11. package/dist/{chunk-XUBYA5I7.mjs → chunk-7ZDS33S2.mjs} +34 -6
  12. package/dist/chunk-7ZDS33S2.mjs.map +1 -0
  13. package/dist/{chunk-SBNENBUQ.mjs → chunk-AXFX2HUK.mjs} +12 -12
  14. package/dist/{chunk-SBNENBUQ.mjs.map → chunk-AXFX2HUK.mjs.map} +1 -1
  15. package/dist/{chunk-54ZQ3FSN.mjs → chunk-BENL3EF2.mjs} +7 -4
  16. package/dist/chunk-BENL3EF2.mjs.map +1 -0
  17. package/dist/{chunk-RTQDQ6TC.mjs → chunk-EHNWQ4T3.mjs} +2 -2
  18. package/dist/{chunk-KBKWVG7X.mjs → chunk-HKJTRBWC.mjs} +5 -5
  19. package/dist/{chunk-JRGCRBWE.mjs → chunk-JCLL7AGP.mjs} +63 -45
  20. package/dist/chunk-JCLL7AGP.mjs.map +1 -0
  21. package/dist/{chunk-ERV7GLY3.mjs → chunk-TVF45U7B.mjs} +5 -5
  22. package/dist/{chunk-H4PBQ5LJ.mjs → chunk-VL3CMSDO.mjs} +4 -4
  23. package/dist/cli.js +44 -44
  24. package/dist/cli.js.map +1 -1
  25. package/dist/{gateway-5yt_3QDP.d.mts → gateway-oScD5tvE.d.mts} +4 -3
  26. package/dist/{gateway-5yt_3QDP.d.ts → gateway-oScD5tvE.d.ts} +4 -3
  27. package/dist/index.d.mts +2 -2
  28. package/dist/index.d.ts +2 -2
  29. package/dist/index.js +159 -67
  30. package/dist/index.js.map +1 -1
  31. package/dist/index.mjs +10 -10
  32. package/dist/management/management.js +159 -67
  33. package/dist/management/management.js.map +1 -1
  34. package/dist/management/management.mjs +8 -8
  35. package/dist/modals/chat-modal/chat-modal.js +53 -18
  36. package/dist/modals/chat-modal/chat-modal.js.map +1 -1
  37. package/dist/modals/chat-modal/chat-modal.mjs +5 -5
  38. package/dist/{modelStore-UMJBDSEF.mjs → modelStore-XWFHNTBT.mjs} +2 -2
  39. package/dist/public-types.d.mts +2 -1
  40. package/dist/public-types.d.ts +2 -1
  41. package/package.json +1 -1
  42. package/dist/chat-7U633EWN.mjs +0 -15
  43. package/dist/chunk-54ZQ3FSN.mjs.map +0 -1
  44. package/dist/chunk-JRGCRBWE.mjs.map +0 -1
  45. package/dist/chunk-QV4ELNLP.mjs.map +0 -1
  46. package/dist/chunk-UXE67LR7.mjs.map +0 -1
  47. package/dist/chunk-XUBYA5I7.mjs.map +0 -1
  48. /package/dist/{aiProviderStore-UQI33C5E.mjs.map → aiProviderStore-3N3VE6D4.mjs.map} +0 -0
  49. /package/dist/{chat-7U633EWN.mjs.map → chat-647M6BRG.mjs.map} +0 -0
  50. /package/dist/{chunk-RTQDQ6TC.mjs.map → chunk-EHNWQ4T3.mjs.map} +0 -0
  51. /package/dist/{chunk-KBKWVG7X.mjs.map → chunk-HKJTRBWC.mjs.map} +0 -0
  52. /package/dist/{chunk-ERV7GLY3.mjs.map → chunk-TVF45U7B.mjs.map} +0 -0
  53. /package/dist/{chunk-H4PBQ5LJ.mjs.map → chunk-VL3CMSDO.mjs.map} +0 -0
  54. /package/dist/{modelStore-UMJBDSEF.mjs.map → modelStore-XWFHNTBT.mjs.map} +0 -0
package/dist/index.js CHANGED
@@ -859,6 +859,27 @@ var init_modelStore = __esm({
859
859
  });
860
860
  }
861
861
  }
862
+ (async () => {
863
+ const storeConfigs6 = [{ name: "config", keyPath: "id" }];
864
+ try {
865
+ const existing = await indexedDBService_default.get("banditConfig", 1, "config", "main", storeConfigs6);
866
+ await indexedDBService_default.put(
867
+ "banditConfig",
868
+ 1,
869
+ "config",
870
+ {
871
+ ...existing,
872
+ id: "main",
873
+ model: { ...existing?.model ?? {}, selectedModel: modelName }
874
+ },
875
+ storeConfigs6
876
+ );
877
+ } catch (err) {
878
+ debugLogger.warn("setSelectedModel: failed to persist selected model", {
879
+ error: err instanceof Error ? err.message : String(err)
880
+ });
881
+ }
882
+ })();
862
883
  },
863
884
  saveModel: async () => {
864
885
  const state = get();
@@ -868,7 +889,8 @@ var init_modelStore = __esm({
868
889
  tagline: state.tagline,
869
890
  systemPrompt: state.systemPrompt,
870
891
  commands: state.commands,
871
- avatarBase64: state.avatarBase64 ?? void 0
892
+ // Ensure avatar changes are persisted even when cleared
893
+ avatarBase64: state.avatarBase64 ?? null
872
894
  };
873
895
  await indexedDBService_default.put("banditConfig", 1, "config", { id: newModel.name, model: newModel }, storeConfigs6);
874
896
  const exists = state.availableModels.find((m) => m.name === newModel.name);
@@ -895,7 +917,12 @@ var init_modelStore = __esm({
895
917
  debugLogger.info("initModels: starting initialization");
896
918
  set({ isLoading: true, isInitializing: true });
897
919
  const storeConfigs6 = [{ name: "config", keyPath: "id" }];
898
- const entries = await indexedDBService_default.getAll("banditConfig", 1, "config", storeConfigs6);
920
+ const entries = await indexedDBService_default.getAll(
921
+ "banditConfig",
922
+ 1,
923
+ "config",
924
+ storeConfigs6
925
+ );
899
926
  const mainEntry = entries.find((entry) => entry.id === "main");
900
927
  const modelEntries = entries.filter((entry) => entry.id !== "main" && entry.id !== "deletedModels");
901
928
  const deletedEntry = await indexedDBService_default.get("banditConfig", 1, "config", "deletedModels", storeConfigs6);
@@ -905,13 +932,14 @@ var init_modelStore = __esm({
905
932
  if (modelEntries.length > 0) {
906
933
  debugLogger.info("Loading models from IndexedDB");
907
934
  allModels = modelEntries.map((entry) => {
908
- const modelData = entry.model?.name ? entry.model : entry;
935
+ const modelData = entry.model ?? entry;
909
936
  return {
910
937
  name: modelData.name,
911
938
  tagline: modelData.tagline || "",
912
939
  systemPrompt: modelData.systemPrompt || "",
913
940
  commands: modelData.commands ?? [],
914
- avatarBase64: modelData.avatarBase64 ?? null
941
+ // Fall back to legacy top-level avatar when the nested model config omitted it
942
+ avatarBase64: modelData.avatarBase64 ?? entry.avatarBase64 ?? null
915
943
  };
916
944
  }).filter((m) => m.name && !deletedModelNames.includes(m.name));
917
945
  const preferences = usePreferencesStore.getState().preferences;
@@ -2140,6 +2168,9 @@ function ensureDeviceId() {
2140
2168
  return (0, import_uuid3.v4)();
2141
2169
  }
2142
2170
  }
2171
+ function getPackageDefaultAdvancedKnowledgeSync() {
2172
+ return usePackageSettingsStore.getState().settings?.advancedKnowledgeSyncDefaultEnabled;
2173
+ }
2143
2174
  function mapConversationToDTO(conversation) {
2144
2175
  const updatedAtIso = (conversation.updatedAt ?? /* @__PURE__ */ new Date()).toISOString();
2145
2176
  const createdAtIso = conversation.createdAt ? conversation.createdAt.toISOString() : null;
@@ -2486,7 +2517,8 @@ function applyPreference(preference, set, getState, options) {
2486
2517
  const override = options?.override ?? {};
2487
2518
  const preferenceVectorFlag = preference.isAdvancedVectorFeaturesEnabled;
2488
2519
  const overrideVectorFlag = override.isAdvancedVectorFeaturesEnabled;
2489
- const resolvedVectorFlag = preferenceVectorFlag !== void 0 ? preferenceVectorFlag : overrideVectorFlag !== void 0 ? overrideVectorFlag : current.isAdvancedVectorFeaturesEnabled ?? false;
2520
+ const packageDefaultVectorFlag = getPackageDefaultAdvancedKnowledgeSync();
2521
+ const resolvedVectorFlag = preferenceVectorFlag !== void 0 ? preferenceVectorFlag : overrideVectorFlag !== void 0 ? overrideVectorFlag : packageDefaultVectorFlag !== void 0 ? packageDefaultVectorFlag : current.isAdvancedVectorFeaturesEnabled ?? false;
2490
2522
  set({
2491
2523
  syncEnabled: preference.syncEnabled,
2492
2524
  status: preference.syncEnabled ? "idle" : "disabled",
@@ -2590,7 +2622,7 @@ var init_conversationSyncStore = __esm({
2590
2622
  cursor: null,
2591
2623
  lastError: null,
2592
2624
  keepLocalOnly: false,
2593
- isAdvancedVectorFeaturesEnabled: false,
2625
+ isAdvancedVectorFeaturesEnabled: getPackageDefaultAdvancedKnowledgeSync() ?? false,
2594
2626
  conflicts: null,
2595
2627
  deviceId: ensureDeviceId(),
2596
2628
  pendingConversationUpserts: /* @__PURE__ */ new Set(),
@@ -2714,7 +2746,7 @@ var init_conversationSyncStore = __esm({
2714
2746
  await get().runSync({ force: true });
2715
2747
  }
2716
2748
  } catch (error) {
2717
- const message = error instanceof Error ? error.message : "Failed to update advanced vector setting";
2749
+ const message = error instanceof Error ? error.message : "Failed to update advanced knowledge setting";
2718
2750
  debugLogger.error("conversationSyncStore: setAdvancedVectorFeaturesEnabled failed", { error: message });
2719
2751
  set({ status: "error", lastError: message });
2720
2752
  throw error;
@@ -4467,7 +4499,7 @@ var init_gateway_service = __esm({
4467
4499
  * Chat completion using the gateway API
4468
4500
  */
4469
4501
  chat(request) {
4470
- const endpoint = request.provider === "ollama" ? `/api/${request.provider}/chat` : request.provider ? `/api/${request.provider}/chat/completions` : "/api/chat/completions";
4502
+ const endpoint = request.provider === "ollama" ? `/api/${request.provider}/chat` : request.provider === "playground" ? "/api/playground/chat/completions" : request.provider ? `/api/${request.provider}/chat/completions` : "/api/chat/completions";
4471
4503
  const fallbackEndpoint = request.provider === "bandit" ? "/completions" : null;
4472
4504
  const normalizedModel = request.provider === "bandit" ? (() => {
4473
4505
  const trimmed = (request.model ?? "").replace(/^bandit:/, "").trim();
@@ -5438,6 +5470,9 @@ var init_gateway_provider = __esm({
5438
5470
  case "ollama":
5439
5471
  this.providerSpecificService = new OllamaGatewayService(gatewayUrl, tokenFactory);
5440
5472
  break;
5473
+ case "playground":
5474
+ this.providerSpecificService = null;
5475
+ break;
5441
5476
  default:
5442
5477
  debugLogger.warn("Unknown provider for gateway, using generic gateway service", {
5443
5478
  provider: this.config.provider
@@ -5468,7 +5503,7 @@ var init_gateway_provider = __esm({
5468
5503
  images: request.images
5469
5504
  };
5470
5505
  }
5471
- } else if (["openai", "azure-openai", "anthropic", "bandit"].includes(this.config.provider || "")) {
5506
+ } else if (["openai", "azure-openai", "anthropic", "bandit", "playground"].includes(this.config.provider || "")) {
5472
5507
  if (lastUserMessageIndex !== -1) {
5473
5508
  const currentMessage = messages[lastUserMessageIndex];
5474
5509
  const contentArray = [
@@ -5515,7 +5550,7 @@ var init_gateway_provider = __esm({
5515
5550
  stream: request.stream,
5516
5551
  hasImages: !!(request.images && request.images.length > 0),
5517
5552
  imageCount: request.images?.length || 0,
5518
- imageStrategy: this.config.provider === "ollama" ? "message-level-array" : ["openai", "azure-openai", "anthropic"].includes(this.config.provider || "") ? "structured-content" : "top-level-fallback",
5553
+ imageStrategy: this.config.provider === "ollama" ? "message-level-array" : ["openai", "azure-openai", "anthropic", "playground"].includes(this.config.provider || "") ? "structured-content" : "top-level-fallback",
5519
5554
  finalMessages: messages.map((m) => ({
5520
5555
  role: m.role,
5521
5556
  hasImages: Array.isArray(m.images) && m.images.length > 0,
@@ -10549,6 +10584,7 @@ var init_custom_logo = __esm({
10549
10584
  init_chat();
10550
10585
  init_brandingService();
10551
10586
  init_debugLogger();
10587
+ init_util();
10552
10588
  import_jsx_runtime4 = require("react/jsx-runtime");
10553
10589
  Logo = ({ visible, atTop = false }) => {
10554
10590
  const theme = (0, import_styles.useTheme)();
@@ -10562,7 +10598,20 @@ var init_custom_logo = __esm({
10562
10598
  const brandingData = await brandingService_default.getBranding();
10563
10599
  if (brandingData) {
10564
10600
  setLogoBase64(brandingData.logoBase64 || null);
10565
- setHasTransparentLogo(brandingData.hasTransparentLogo ?? true);
10601
+ if (brandingData.logoBase64) {
10602
+ try {
10603
+ const detected = await detectTransparency(brandingData.logoBase64);
10604
+ const isPng = brandingData.logoBase64.startsWith("data:image/png");
10605
+ const finalTransparent = detected || isPng || brandingData.hasTransparentLogo === true;
10606
+ setHasTransparentLogo(finalTransparent);
10607
+ } catch {
10608
+ const isPng = brandingData.logoBase64.startsWith("data:image/png");
10609
+ const finalTransparent = brandingData.hasTransparentLogo === true || isPng;
10610
+ setHasTransparentLogo(finalTransparent);
10611
+ }
10612
+ } else {
10613
+ setHasTransparentLogo(brandingData.hasTransparentLogo ?? true);
10614
+ }
10566
10615
  }
10567
10616
  } catch (e) {
10568
10617
  debugLogger.error("Failed to load branding from service", { error: e });
@@ -10572,7 +10621,7 @@ var init_custom_logo = __esm({
10572
10621
  };
10573
10622
  loadBranding();
10574
10623
  }, []);
10575
- return logoBase64 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: loading ? null : hasTransparentLogo ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
10624
+ return logoBase64 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: loading ? null : hasTransparentLogo !== false ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
10576
10625
  import_material2.Box,
10577
10626
  {
10578
10627
  component: "img",
@@ -10584,7 +10633,8 @@ var init_custom_logo = __esm({
10584
10633
  maxWidth: 600,
10585
10634
  aspectRatio: "1 / 1",
10586
10635
  margin: "0 auto",
10587
- mt: atTop ? 2 : 6
10636
+ mt: atTop ? 2 : 6,
10637
+ display: "block"
10588
10638
  }
10589
10639
  }
10590
10640
  ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -10626,8 +10676,8 @@ var init_chat_scroll_to_bottom_button = __esm({
10626
10676
  drawerOpen = false,
10627
10677
  isMobile = false
10628
10678
  }) => {
10629
- const verticalBuffer = isMobile ? 36 : 56;
10630
- const bottomOffset = Math.max(inputHeight + verticalBuffer, verticalBuffer + 72);
10679
+ const verticalBuffer = isMobile ? 28 : 48;
10680
+ const bottomOffset = Math.max(inputHeight + verticalBuffer, verticalBuffer + 64);
10631
10681
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
10632
10682
  import_material3.IconButton,
10633
10683
  {
@@ -10643,9 +10693,12 @@ var init_chat_scroll_to_bottom_button = __esm({
10643
10693
  borderColor: (theme) => theme.palette.divider,
10644
10694
  zIndex: (theme) => Math.max(theme.zIndex.modal + 1, 1400),
10645
10695
  boxShadow: 3,
10646
- transition: "bottom 0.3s ease, left 0.3s ease-in-out",
10696
+ transition: "bottom 0.25s ease, left 0.3s ease-in-out, transform 0.2s ease",
10647
10697
  "&:hover": {
10648
10698
  bgcolor: (theme) => theme.palette.action.hover
10699
+ },
10700
+ "&:active": {
10701
+ transform: "translateX(-50%) translateY(1px)"
10649
10702
  }
10650
10703
  },
10651
10704
  children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ArrowDownward.default, { sx: { color: "inherit" } })
@@ -15660,7 +15713,7 @@ var init_memory_modal = __esm({
15660
15713
  children: [
15661
15714
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material11.Box, { sx: { display: "flex", alignItems: "center", gap: 0.75 }, children: [
15662
15715
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material11.Typography, { variant: "h6", sx: { fontWeight: 600 }, children: "Memory" }),
15663
- shouldUseVectorForMemories && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material11.Tooltip, { title: "Memories are stored in an AI vector database with semantic search capabilities", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
15716
+ shouldUseVectorForMemories && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material11.Tooltip, { title: "Memories stay in your private knowledge space for faster, more accurate answers.", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
15664
15717
  import_material11.Typography,
15665
15718
  {
15666
15719
  variant: "caption",
@@ -15675,7 +15728,7 @@ var init_memory_modal = __esm({
15675
15728
  textTransform: "uppercase",
15676
15729
  cursor: "help"
15677
15730
  },
15678
- children: "Vector"
15731
+ children: "Synced"
15679
15732
  }
15680
15733
  ) })
15681
15734
  ] }),
@@ -15774,7 +15827,7 @@ var init_memory_modal = __esm({
15774
15827
  onClick: () => setBulkImportOpen(true),
15775
15828
  startIcon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_CloudSync.default, {}),
15776
15829
  sx: { textTransform: "none", borderRadius: 2, fontSize: "0.75rem" },
15777
- children: "Import to Vector"
15830
+ children: "Import to workspace"
15778
15831
  }
15779
15832
  ),
15780
15833
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
@@ -16016,7 +16069,7 @@ var init_memory_modal = __esm({
16016
16069
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material11.Typography, { variant: "body2", sx: {
16017
16070
  color: (0, import_styles6.alpha)(theme.palette.text.secondary, 0.7),
16018
16071
  maxWidth: 280
16019
- }, children: selectedTab === "user" ? shouldUseVectorForMemories ? "Start by adding something you'd like me to remember. Your memories will be stored in the AI vector database for intelligent retrieval." : "Start by adding something you'd like me to remember about you or your preferences." : shouldUseVectorForMemories ? "Auto memories are created automatically based on our conversations and stored in the vector database for semantic search." : "Auto memories are created automatically based on our conversations." })
16072
+ }, children: selectedTab === "user" ? shouldUseVectorForMemories ? "Start by adding something you'd like me to remember. Your memories will be kept in a private workspace for quick recall." : "Start by adding something you'd like me to remember about you or your preferences." : shouldUseVectorForMemories ? "Auto memories are created automatically based on our conversations and kept in your private workspace for better answers." : "Auto memories are created automatically based on our conversations." })
16020
16073
  ] }) : filteredMemories.map((memory) => {
16021
16074
  const isSelected = selectedIds.includes(memory.id);
16022
16075
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react17.default.Fragment, { children: [
@@ -16288,7 +16341,7 @@ var init_memory_modal = __esm({
16288
16341
  size: "small",
16289
16342
  value: newMemory,
16290
16343
  onChange: (e) => setNewMemory(e.target.value),
16291
- placeholder: shouldUseVectorForMemories ? `Add a new ${selectedTab} memory to vector database...` : `Add a new ${selectedTab} memory...`,
16344
+ placeholder: shouldUseVectorForMemories ? `Add a new ${selectedTab} memory to your workspace...` : `Add a new ${selectedTab} memory...`,
16292
16345
  onKeyDown: (e) => {
16293
16346
  if (e.key === "Enter" && !e.shiftKey && newMemory.trim()) {
16294
16347
  e.preventDefault();
@@ -16528,15 +16581,15 @@ var init_memory_modal = __esm({
16528
16581
  gap: 1
16529
16582
  }, children: [
16530
16583
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_CloudSync.default, { color: "primary" }),
16531
- "Import Memories to Vector Database"
16584
+ "Import Memories to Secure Workspace"
16532
16585
  ] }),
16533
16586
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material11.DialogContent, { sx: { py: 2 }, children: !importProgress.isImporting ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material11.Box, { children: [
16534
16587
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material11.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: [
16535
16588
  "This will import all your local memories (",
16536
16589
  entries.length,
16537
- " memories) to the vector database for enhanced semantic search capabilities."
16590
+ " memories) to your secure workspace for faster, more reliable answers."
16538
16591
  ] }),
16539
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material11.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: "\u2022 Memories will be added to your vector storage \u2022 Local memories will remain unchanged \u2022 You can switch between local and vector storage anytime" }),
16592
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material11.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: "\u2022 Memories will be added to your synced workspace \u2022 Local memories will remain unchanged \u2022 You can switch between synced and local storage anytime" }),
16540
16593
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material11.Typography, { variant: "body2", color: "primary", sx: { fontWeight: 500 }, children: [
16541
16594
  "Ready to import ",
16542
16595
  entries.length,
@@ -24202,9 +24255,18 @@ var init_chat_app_bar = __esm({
24202
24255
  const currentModel = useModelStore((s) => s.availableModels.find((m) => m.name === selectedModel));
24203
24256
  const currentAvatar = currentModel?.avatarBase64 || modelAvatars2[selectedModel] || banditHead3;
24204
24257
  const pendingModelAvatar = useModelStore.getState().availableModels.find((m) => m.name === pendingModel)?.avatarBase64 || modelAvatars2[pendingModel || ""] || banditHead3;
24258
+ const resolvedHomeUrl = preferences.homeUrl?.trim() || packageSettings?.homeUrl?.trim() || "";
24259
+ const homeTooltip = (() => {
24260
+ if (!resolvedHomeUrl) return "Home";
24261
+ try {
24262
+ return `Home (${new URL(resolvedHomeUrl).hostname})`;
24263
+ } catch {
24264
+ return "Home";
24265
+ }
24266
+ })();
24205
24267
  function goToHome() {
24206
- if (preferences.homeUrl && preferences.homeUrl.trim()) {
24207
- window.location.href = preferences.homeUrl;
24268
+ if (resolvedHomeUrl) {
24269
+ window.location.href = resolvedHomeUrl;
24208
24270
  return;
24209
24271
  }
24210
24272
  if (typeof window !== "undefined") {
@@ -24267,7 +24329,7 @@ var init_chat_app_bar = __esm({
24267
24329
  }
24268
24330
  },
24269
24331
  children: [
24270
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material22.Tooltip, { title: preferences.homeUrl && preferences.homeUrl.trim() ? `Home (${new URL(preferences.homeUrl).hostname})` : "Home", arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
24332
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material22.Tooltip, { title: homeTooltip, arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
24271
24333
  import_material22.IconButton,
24272
24334
  {
24273
24335
  onClick: goToHome,
@@ -24551,9 +24613,15 @@ var init_chat_app_bar = __esm({
24551
24613
  (async () => {
24552
24614
  try {
24553
24615
  const storeConfigs6 = [{ name: "config", keyPath: "id" }];
24554
- const current = await indexedDBService_default.get("banditConfig", 1, "config", "main", storeConfigs6);
24616
+ const current = await indexedDBService_default.get(
24617
+ "banditConfig",
24618
+ 1,
24619
+ "config",
24620
+ "main",
24621
+ storeConfigs6
24622
+ );
24555
24623
  const updated = {
24556
- ...current,
24624
+ ...current ?? {},
24557
24625
  id: "main",
24558
24626
  model: {
24559
24627
  ...current?.model || {},
@@ -24745,9 +24813,15 @@ var init_chat_app_bar = __esm({
24745
24813
  (async () => {
24746
24814
  try {
24747
24815
  const storeConfigs6 = [{ name: "config", keyPath: "id" }];
24748
- const current = await indexedDBService_default.get("banditConfig", 1, "config", "main", storeConfigs6);
24816
+ const current = await indexedDBService_default.get(
24817
+ "banditConfig",
24818
+ 1,
24819
+ "config",
24820
+ "main",
24821
+ storeConfigs6
24822
+ );
24749
24823
  const updated = {
24750
- ...current,
24824
+ ...current ?? {},
24751
24825
  id: "main",
24752
24826
  model: {
24753
24827
  ...current?.model || {},
@@ -34676,7 +34750,7 @@ var PreferencesTab = ({
34676
34750
  await setAdvancedVectorFeaturesEnabled(enabled);
34677
34751
  if (showSnackbar) {
34678
34752
  showSnackbar(
34679
- enabled ? "Advanced vector features enabled for this account." : "Advanced vector features disabled.",
34753
+ enabled ? "Advanced knowledge sync enabled for this account." : "Advanced knowledge sync disabled.",
34680
34754
  "success"
34681
34755
  );
34682
34756
  }
@@ -34961,8 +35035,8 @@ var PreferencesTab = ({
34961
35035
  }
34962
35036
  ),
34963
35037
  label: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_material37.Box, { textAlign: "left", children: [
34964
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_material37.Typography, { variant: "body1", sx: { fontWeight: 600, color: "text.primary" }, children: "Advanced vector features" }),
34965
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_material37.Typography, { variant: "body2", color: "text.secondary", children: "Keep semantic search, vector memories, and related context in sync across devices" })
35038
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_material37.Typography, { variant: "body1", sx: { fontWeight: 600, color: "text.primary" }, children: "Advanced knowledge sync" }),
35039
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_material37.Typography, { variant: "body2", color: "text.secondary", children: "Keep richer search, saved memories, and context in sync across devices" })
34966
35040
  ] }),
34967
35041
  sx: { alignSelf: { xs: "flex-start", sm: "center" } }
34968
35042
  }
@@ -35532,6 +35606,7 @@ var LogoCropper = ({
35532
35606
  canvas.width = outputWidth;
35533
35607
  canvas.height = outputHeight;
35534
35608
  ctx.save();
35609
+ ctx.clearRect(0, 0, outputWidth, outputHeight);
35535
35610
  const scaleX = outputWidth / cropDims.width;
35536
35611
  const scaleY = outputHeight / cropDims.height;
35537
35612
  ctx.translate(outputWidth / 2, outputHeight / 2);
@@ -36572,30 +36647,29 @@ var defaultSteps = [
36572
36647
  },
36573
36648
  {
36574
36649
  id: "embed",
36575
- title: "Creating Vectors",
36576
- description: "Neural networks are encoding knowledge into searchable vectors...",
36650
+ title: "Making It Searchable",
36651
+ description: "We turn the content into a private, searchable index...",
36577
36652
  icon: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_icons_material12.Memory, {}),
36578
36653
  duration: 10
36579
36654
  },
36580
36655
  {
36581
36656
  id: "optimize",
36582
36657
  title: "Optimizing Search",
36583
- description: "AI algorithms are organizing data for lightning-fast retrieval...",
36658
+ description: "Organizing everything for quick, reliable answers...",
36584
36659
  icon: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_icons_material12.AutoAwesome, {}),
36585
36660
  duration: 8
36586
36661
  }
36587
36662
  ];
36588
36663
  var cleverMessages = [
36589
- "\u{1F977} Digital ninjas are working their magic...",
36590
- "\u{1F916} AI robots are crunching your data...",
36591
- "\u26A1 Neural networks firing at maximum capacity...",
36592
- "\u{1F9E0} Machine learning models deep in thought...",
36593
- "\u{1F52E} AI wizards casting knowledge spells...",
36594
- "\u2699\uFE0F Quantum processors spinning up...",
36595
- "\u{1F680} Algorithms achieving warp speed...",
36596
- "\u{1F4AB} Creating digital memories from your content...",
36597
- "\u{1F3AF} Precision-targeting knowledge patterns...",
36598
- "\u{1F31F} Transforming text into searchable stardust..."
36664
+ "\u{1F977} Keeping your content safe while we set things up...",
36665
+ "\u{1F916} Getting everything ready for fast answers...",
36666
+ "\u26A1 Tidying the data so responses stay consistent...",
36667
+ "\u{1F9E0} Remembering the important parts for you...",
36668
+ "\u{1F512} Locking in privacy before we share results...",
36669
+ "\u{1F680} Optimizing for quick, reliable lookups...",
36670
+ "\u{1F4AB} Turning this into searchable knowledge...",
36671
+ "\u{1F3AF} Focusing on the details that matter to you...",
36672
+ "\u{1F31F} Making sure it stays available when you need it..."
36599
36673
  ];
36600
36674
  var ProcessingOverlay = ({
36601
36675
  open,
@@ -37184,16 +37258,16 @@ var KnowledgeTab = ({
37184
37258
  const handleDocumentUpload = async (files) => {
37185
37259
  if (shouldUseVector) {
37186
37260
  showProcessing(
37187
- "Uploading to Vector Database",
37261
+ "Uploading to Secure Workspace",
37188
37262
  [
37189
- "\u{1F977} Digital ninjas securing your documents...",
37190
- "\u{1F916} AI robots reading and understanding content...",
37191
- "\u26A1 Neural networks encoding knowledge vectors...",
37192
- "\u{1F9E0} Machine learning creating searchable memories...",
37193
- "\u{1F52E} AI wizards optimizing semantic search...",
37194
- "\u{1F680} Vector embeddings achieving light speed...",
37195
- "\u{1F4AB} Transforming documents into intelligent data...",
37196
- "\u{1F3AF} Precision-targeting knowledge patterns..."
37263
+ "\u{1F977} Keeping your documents private while we prepare them...",
37264
+ "\u{1F916} Reading the content so answers stay accurate...",
37265
+ "\u26A1 Turning pages into a searchable index...",
37266
+ "\u{1F9E0} Remembering highlights for quick recall...",
37267
+ "\u{1F52E} Organizing everything so search feels instant...",
37268
+ "\u{1F680} Optimizing for fast, consistent responses...",
37269
+ "\u{1F4AB} Transforming documents into trusted knowledge...",
37270
+ "\u{1F3AF} Focusing on the details that matter most..."
37197
37271
  ]
37198
37272
  );
37199
37273
  try {
@@ -37267,7 +37341,7 @@ var KnowledgeTab = ({
37267
37341
  progress: 100,
37268
37342
  status: "success"
37269
37343
  })));
37270
- const message = result.usedVector ? `Successfully uploaded ${files.length} document(s) to vector database` : result.error ? `Upload completed with warnings: ${result.error}` : `Successfully uploaded ${files.length} document(s)`;
37344
+ const message = result.usedVector ? `Successfully uploaded ${files.length} document(s) to your secure workspace` : result.error ? `Upload completed with warnings: ${result.error}` : `Successfully uploaded ${files.length} document(s)`;
37271
37345
  setSnackbarMessage(message);
37272
37346
  setSnackbarSeverity(result.error ? "warning" : "success");
37273
37347
  setShowSnackbar(true);
@@ -37328,7 +37402,7 @@ var KnowledgeTab = ({
37328
37402
  progress: 100,
37329
37403
  status: "success"
37330
37404
  })));
37331
- const message = result.usedVector ? `Successfully uploaded ${files.length} document(s) to vector database` : result.error ? `Upload completed with warnings: ${result.error}` : `Successfully uploaded ${files.length} document(s)`;
37405
+ const message = result.usedVector ? `Successfully uploaded ${files.length} document(s) to your secure workspace` : result.error ? `Upload completed with warnings: ${result.error}` : `Successfully uploaded ${files.length} document(s)`;
37332
37406
  setSnackbarMessage(message);
37333
37407
  setSnackbarSeverity(result.error ? "warning" : "success");
37334
37408
  setShowSnackbar(true);
@@ -37506,7 +37580,7 @@ var KnowledgeTab = ({
37506
37580
  shouldUseVector && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
37507
37581
  import_material41.Chip,
37508
37582
  {
37509
- label: "Vector DB",
37583
+ label: "Synced",
37510
37584
  color: "primary",
37511
37585
  size: "small",
37512
37586
  sx: { ml: 1 }
@@ -37523,7 +37597,7 @@ var KnowledgeTab = ({
37523
37597
  sx: { fontSize: { xs: "0.95rem", sm: "1rem" }, lineHeight: 1.5 },
37524
37598
  children: [
37525
37599
  "Add documents to your private knowledge base. Files are securely stored ",
37526
- shouldUseVector ? "in the vector database" : "locally in your browser",
37600
+ shouldUseVector ? "in your private workspace" : "locally in your browser",
37527
37601
  "."
37528
37602
  ]
37529
37603
  }
@@ -37859,7 +37933,7 @@ var KnowledgeTab = ({
37859
37933
  filteredAndSortedDocuments.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_material41.Card, { sx: { textAlign: "center", py: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_material41.CardContent, { children: [
37860
37934
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_Folder.default, { sx: { fontSize: 64, color: "text.secondary", mb: 2 } }),
37861
37935
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_material41.Typography, { variant: "h6", color: "text.secondary", gutterBottom: true, children: "No Documents Yet" }),
37862
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_material41.Typography, { variant: "body2", color: "text.secondary", children: shouldUseVector ? "Upload and embed your first document to get started with advanced vector search" : "Upload your first document to get started" })
37936
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_material41.Typography, { variant: "body2", color: "text.secondary", children: shouldUseVector ? "Upload and embed your first document to get started with advanced search" : "Upload your first document to get started" })
37863
37937
  ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_material41.Box, { children: [
37864
37938
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_material41.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: [
37865
37939
  "Showing ",
@@ -37868,7 +37942,7 @@ var KnowledgeTab = ({
37868
37942
  shouldUseVector ? vectorDocuments.length : documents.length,
37869
37943
  " documents",
37870
37944
  searchQuery && ` for "${searchQuery}"`,
37871
- shouldUseVector && ` (Vector Database)`
37945
+ shouldUseVector && ` (Synced workspace)`
37872
37946
  ] }),
37873
37947
  viewMode === "grid" ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
37874
37948
  import_material41.Box,
@@ -40378,6 +40452,7 @@ var Management = () => {
40378
40452
  name: modelToSave.name,
40379
40453
  tagline: modelToSave.tagline,
40380
40454
  systemPrompt: modelToSave.systemPrompt,
40455
+ avatarBase64: modelToSave.avatarBase64 || void 0,
40381
40456
  selectedModel: modelToSave.name
40382
40457
  }
40383
40458
  };
@@ -40430,6 +40505,19 @@ var Management = () => {
40430
40505
  try {
40431
40506
  const storeConfigs6 = [{ name: "config", keyPath: "id" }];
40432
40507
  debugLogger.info("Saving branding data to IndexedDB");
40508
+ let finalHasTransparentLogo = hasTransparentLogo;
40509
+ if (logoBase64) {
40510
+ try {
40511
+ const detected = await detectTransparency(logoBase64);
40512
+ const isPng = logoBase64.startsWith("data:image/png");
40513
+ finalHasTransparentLogo = detected || isPng;
40514
+ debugLogger.debug("SaveBranding transparency check", { detected, isPng, finalHasTransparentLogo });
40515
+ } catch (err) {
40516
+ const isPng = logoBase64.startsWith("data:image/png");
40517
+ finalHasTransparentLogo = finalHasTransparentLogo ?? isPng ?? true;
40518
+ debugLogger.warn("SaveBranding transparency check failed, using fallback", { error: err, finalHasTransparentLogo });
40519
+ }
40520
+ }
40433
40521
  const current = await indexedDBService_default.get(
40434
40522
  "banditConfig",
40435
40523
  1,
@@ -40445,7 +40533,7 @@ var Management = () => {
40445
40533
  logoBase64,
40446
40534
  brandingText,
40447
40535
  theme,
40448
- hasTransparentLogo,
40536
+ hasTransparentLogo: finalHasTransparentLogo,
40449
40537
  userSaved: true
40450
40538
  // Mark as user-saved to protect from CDN overrides
40451
40539
  }
@@ -40484,9 +40572,11 @@ var Management = () => {
40484
40572
  setLogoBase64(base64);
40485
40573
  debugLogger.debug("Starting transparency detection for uploaded image");
40486
40574
  try {
40575
+ const isPng = base64.startsWith("data:image/png");
40487
40576
  const isTransparent = await detectTransparency(base64);
40488
- setHasTransparentLogo(isTransparent);
40489
- debugLogger.debug("Transparency detection result saved", { isTransparent });
40577
+ const finalTransparent = isTransparent || isPng;
40578
+ setHasTransparentLogo(finalTransparent);
40579
+ debugLogger.debug("Transparency detection result saved", { isTransparent, finalTransparent });
40490
40580
  } catch (err) {
40491
40581
  debugLogger.error("Failed to detect transparency", { error: err });
40492
40582
  }
@@ -40699,7 +40789,8 @@ var Management = () => {
40699
40789
  name: modelName2,
40700
40790
  tagline: typeof parsedModel.tagline === "string" ? parsedModel.tagline : void 0,
40701
40791
  systemPrompt: typeof parsedModel.systemPrompt === "string" ? parsedModel.systemPrompt : void 0,
40702
- selectedModel: typeof parsedModel.selectedModel === "string" ? parsedModel.selectedModel : void 0
40792
+ selectedModel: typeof parsedModel.selectedModel === "string" ? parsedModel.selectedModel : void 0,
40793
+ avatarBase64: typeof parsedModel.avatarBase64 === "string" ? parsedModel.avatarBase64 : parsedModel.avatarBase64 === null ? void 0 : void 0
40703
40794
  };
40704
40795
  const entry = {
40705
40796
  id: modelName2,
@@ -40707,7 +40798,8 @@ var Management = () => {
40707
40798
  name: modelName2,
40708
40799
  tagline: sanitizedModel.tagline,
40709
40800
  systemPrompt: sanitizedModel.systemPrompt,
40710
- avatarBase64: typeof parsedModel.avatarBase64 === "string" ? parsedModel.avatarBase64 : void 0
40801
+ // Normalize to match StoredBanditConfigRecord (string | undefined)
40802
+ avatarBase64: sanitizedModel.avatarBase64 ?? void 0
40711
40803
  };
40712
40804
  await indexedDBService_default.put("banditConfig", 1, "config", entry, storeConfigs6);
40713
40805
  }