@burtson-labs/bandit-engine 2.0.129 → 2.0.131

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.
@@ -13090,7 +13090,8 @@ var init_ai_response_text_field = __esm({
13090
13090
  memoryUpdated,
13091
13091
  sourceFiles,
13092
13092
  isMobile = false,
13093
- cancelled = false
13093
+ cancelled = false,
13094
+ revealActionsOnHover = false
13094
13095
  }) => {
13095
13096
  (0, import_react14.useEffect)(() => {
13096
13097
  if (typeof response !== "string" && !import_react14.default.isValidElement(response)) {
@@ -13578,7 +13579,8 @@ ${sourcesMarkdownList.join("\n")}`;
13578
13579
  color: chatResponse.aiText || theme.palette.text.primary,
13579
13580
  px: isMobile ? 0.5 : 2,
13580
13581
  py: 1,
13581
- userSelect: "text"
13582
+ userSelect: "text",
13583
+ "&:hover .ai-response-actions": { opacity: 1 }
13582
13584
  },
13583
13585
  children: [
13584
13586
  /* @__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: [
@@ -13678,7 +13680,18 @@ ${sourcesMarkdownList.join("\n")}`;
13678
13680
  }
13679
13681
  ) : import_react14.default.isValidElement(response) ? response : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material8.Typography, { color: "error", children: "\u26A0\uFE0F Invalid AI response" }) })
13680
13682
  ] }),
13681
- !!(responseText || typeof response === "string" && response) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ai_response_action_bar_default, { text: responseText || response }),
13683
+ !!(responseText || typeof response === "string" && response) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
13684
+ import_material8.Box,
13685
+ {
13686
+ className: "ai-response-actions",
13687
+ sx: revealActionsOnHover ? {
13688
+ opacity: 0,
13689
+ transition: "opacity 0.15s ease",
13690
+ "&:focus-within": { opacity: 1 }
13691
+ } : void 0,
13692
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ai_response_action_bar_default, { text: responseText || response })
13693
+ }
13694
+ ),
13682
13695
  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) => {
13683
13696
  debugLogger.debug("Rendering DocumentCard in AI response", {
13684
13697
  index: idx,
@@ -16361,152 +16374,6 @@ var init_FeedbackModal = __esm({
16361
16374
  }
16362
16375
  });
16363
16376
 
16364
- // src/components/feedback/index.tsx
16365
- var init_feedback = __esm({
16366
- "src/components/feedback/index.tsx"() {
16367
- "use strict";
16368
- init_FeedbackButton();
16369
- init_FeedbackModal();
16370
- }
16371
- });
16372
-
16373
- // src/components/feedback/FeedbackButton.tsx
16374
- var import_react18, import_material14, import_lucide_react4, import_jsx_runtime14, FeedbackButton;
16375
- var init_FeedbackButton = __esm({
16376
- "src/components/feedback/FeedbackButton.tsx"() {
16377
- "use strict";
16378
- import_react18 = require("react");
16379
- import_material14 = require("@mui/material");
16380
- import_lucide_react4 = require("lucide-react");
16381
- init_feedback();
16382
- import_jsx_runtime14 = require("react/jsx-runtime");
16383
- FeedbackButton = ({
16384
- fullScreen = false,
16385
- className,
16386
- zIndex = 1400,
16387
- feedbackEmail,
16388
- inline = false,
16389
- buttonText = "Send Feedback",
16390
- size = "small",
16391
- position,
16392
- absolute = false
16393
- }) => {
16394
- const theme = (0, import_material14.useTheme)();
16395
- const [open, setOpen] = (0, import_react18.useState)(false);
16396
- const handleOpen = () => setOpen(true);
16397
- const handleClose = () => setOpen(false);
16398
- if (inline) {
16399
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
16400
- buttonText ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
16401
- import_material14.Button,
16402
- {
16403
- variant: "outlined",
16404
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.MessageCircle, {}),
16405
- onClick: handleOpen,
16406
- className,
16407
- size,
16408
- sx: {
16409
- borderRadius: 2,
16410
- textTransform: "none",
16411
- "&:hover": {
16412
- transform: "translateY(-1px)",
16413
- boxShadow: theme.shadows[4]
16414
- }
16415
- },
16416
- children: buttonText
16417
- }
16418
- ) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material14.Tooltip, { title: "Send Feedback", arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
16419
- import_material14.IconButton,
16420
- {
16421
- onClick: handleOpen,
16422
- className,
16423
- size,
16424
- sx: {
16425
- color: theme.palette.primary.main,
16426
- borderRadius: 2,
16427
- transition: "all 0.2s ease",
16428
- "&:hover": {
16429
- bgcolor: theme.palette.primary.main + "15",
16430
- transform: "translateY(-1px)"
16431
- }
16432
- },
16433
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.MessageCircle, {})
16434
- }
16435
- ) }),
16436
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
16437
- FeedbackModal,
16438
- {
16439
- open,
16440
- onClose: handleClose,
16441
- feedbackEmail
16442
- }
16443
- )
16444
- ] });
16445
- }
16446
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
16447
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material14.Zoom, { in: true, timeout: 300, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
16448
- import_material14.Tooltip,
16449
- {
16450
- title: "Send Feedback",
16451
- placement: "left",
16452
- arrow: true,
16453
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
16454
- import_material14.Fab,
16455
- {
16456
- size,
16457
- onClick: handleOpen,
16458
- className,
16459
- sx: {
16460
- position: absolute ? "absolute" : "relative",
16461
- ...absolute && {
16462
- bottom: position?.bottom ?? (fullScreen ? 16 : 20),
16463
- right: position?.right ?? 16,
16464
- top: position?.top,
16465
- left: position?.left
16466
- },
16467
- zIndex,
16468
- bgcolor: theme.palette.primary.main,
16469
- color: theme.palette.primary.contrastText,
16470
- boxShadow: theme.palette.mode === "dark" ? "0 8px 32px rgba(0,0,0,0.4)" : "0 8px 32px rgba(0,0,0,0.15)",
16471
- border: `1px solid ${theme.palette.divider}`,
16472
- transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
16473
- "&:hover": {
16474
- bgcolor: theme.palette.primary.dark,
16475
- transform: "scale(1.05) translateY(-2px)",
16476
- boxShadow: theme.palette.mode === "dark" ? "0 12px 40px rgba(0,0,0,0.5)" : "0 12px 40px rgba(0,0,0,0.2)"
16477
- },
16478
- "&:active": {
16479
- transform: "scale(0.98) translateY(0px)"
16480
- },
16481
- // Subtle pulsing animation
16482
- animation: "feedbackPulse 3s ease-in-out infinite",
16483
- "@keyframes feedbackPulse": {
16484
- "0%, 100%": {
16485
- boxShadow: theme.palette.mode === "dark" ? "0 8px 32px rgba(0,0,0,0.4)" : "0 8px 32px rgba(0,0,0,0.15)"
16486
- },
16487
- "50%": {
16488
- boxShadow: theme.palette.mode === "dark" ? `0 8px 32px ${theme.palette.primary.main}40` : `0 8px 32px ${theme.palette.primary.main}30`
16489
- }
16490
- }
16491
- },
16492
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.MessageCircle, {})
16493
- }
16494
- )
16495
- }
16496
- ) }),
16497
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
16498
- FeedbackModal,
16499
- {
16500
- open,
16501
- onClose: handleClose,
16502
- feedbackEmail
16503
- }
16504
- )
16505
- ] });
16506
- };
16507
- }
16508
- });
16509
-
16510
16377
  // src/shared/components/NotificationProvider.tsx
16511
16378
  var import_react21, import_material16, import_jsx_runtime15, NotificationContext, useNotification;
16512
16379
  var init_NotificationProvider = __esm({
@@ -20570,7 +20437,7 @@ var init_source_chips = __esm({
20570
20437
  });
20571
20438
 
20572
20439
  // src/chat/chat-messages.tsx
20573
- var import_material36, import_jsx_runtime36, WORKING_TOKEN_RE, ToolWorkingChip, ChatMessages, chat_messages_default;
20440
+ var import_material36, import_jsx_runtime36, WORKING_TOKEN_RE, BYTE_TOKEN_RUN_RE, decodeByteTokens, ToolWorkingChip, ChatMessages, chat_messages_default;
20574
20441
  var init_chat_messages = __esm({
20575
20442
  "src/chat/chat-messages.tsx"() {
20576
20443
  "use strict";
@@ -20581,6 +20448,18 @@ var init_chat_messages = __esm({
20581
20448
  init_conversationStore();
20582
20449
  import_jsx_runtime36 = require("react/jsx-runtime");
20583
20450
  WORKING_TOKEN_RE = /\s*<<working:([^>]*)>>\s*$/;
20451
+ BYTE_TOKEN_RUN_RE = /(?:<0x[0-9A-Fa-f]{2}>)+/g;
20452
+ decodeByteTokens = (text) => {
20453
+ if (!text || text.indexOf("<0x") === -1) return text;
20454
+ return text.replace(BYTE_TOKEN_RUN_RE, (run) => {
20455
+ const bytes = Array.from(run.matchAll(/<0x([0-9A-Fa-f]{2})>/g), (m) => parseInt(m[1], 16));
20456
+ try {
20457
+ return new TextDecoder("utf-8", { fatal: true }).decode(new Uint8Array(bytes));
20458
+ } catch {
20459
+ return "";
20460
+ }
20461
+ });
20462
+ };
20584
20463
  ToolWorkingChip = ({ label }) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
20585
20464
  import_material36.Box,
20586
20465
  {
@@ -20631,7 +20510,7 @@ var init_chat_messages = __esm({
20631
20510
  const lastIndex = history.length - 1;
20632
20511
  const hasActivePlaceholder = lastIndex >= 0 && history[lastIndex]?.answer === "...";
20633
20512
  if (!responseStarted && !pendingMessage && history.length === 0) return null;
20634
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_material36.Box, { sx: { px: isMobile ? 0 : 0, pt: "100px", display: "flex", flexDirection: "column", gap: 2 }, children: [
20513
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_material36.Box, { sx: { px: isMobile ? 0 : 0, pt: "calc(100px + env(safe-area-inset-top, 0px))", display: "flex", flexDirection: "column", gap: 2 }, children: [
20635
20514
  history.map((entry, index) => {
20636
20515
  const isLast = index === lastIndex;
20637
20516
  const isPlaceholder = entry.answer === "...";
@@ -20639,7 +20518,9 @@ var init_chat_messages = __esm({
20639
20518
  const showThinking = showLoader && isThinking;
20640
20519
  const rawContent = isLast ? isStreaming ? streamBuffer || "" : isPlaceholder ? "" : entry.answer : entry.answer;
20641
20520
  const workingMatch = isLast && isStreaming ? rawContent.match(WORKING_TOKEN_RE) : null;
20642
- const content = workingMatch ? rawContent.replace(WORKING_TOKEN_RE, "") : rawContent;
20521
+ const content = decodeByteTokens(
20522
+ workingMatch ? rawContent.replace(WORKING_TOKEN_RE, "") : rawContent
20523
+ );
20643
20524
  const rawSources = entry.sourceFiles;
20644
20525
  const sourceSummaries = rawSources ? rawSources.filter((doc) => doc && typeof doc.name === "string" && doc.name.trim()).map((doc) => ({ id: doc.id || doc.name, name: doc.name.trim() })) : void 0;
20645
20526
  const responseNode = /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
@@ -20731,7 +20612,8 @@ var init_chat_messages = __esm({
20731
20612
  memoryUpdated: entry.memoryUpdated && !isPlaceholder,
20732
20613
  sourceFiles: rawSources,
20733
20614
  isMobile,
20734
- cancelled: entry.cancelled
20615
+ cancelled: entry.cancelled,
20616
+ revealActionsOnHover: !isLast && !isMobile
20735
20617
  }
20736
20618
  ) }, index);
20737
20619
  }),
@@ -26862,6 +26744,7 @@ var init_conversation_drawer = __esm({
26862
26744
  import_react57 = require("react");
26863
26745
  import_material46 = require("@mui/material");
26864
26746
  import_lucide_react14 = require("lucide-react");
26747
+ init_FeedbackModal();
26865
26748
  import_styles30 = require("@mui/material/styles");
26866
26749
  init_conversationStore();
26867
26750
  init_projectStore();
@@ -26937,6 +26820,7 @@ var init_conversation_drawer = __esm({
26937
26820
  const [searchQuery, setSearchQuery] = (0, import_react57.useState)("");
26938
26821
  const [menuAnchorEl, setMenuAnchorEl] = (0, import_react57.useState)(null);
26939
26822
  const [clearConfirmOpen, setClearConfirmOpen] = (0, import_react57.useState)(false);
26823
+ const [feedbackOpen, setFeedbackOpen] = (0, import_react57.useState)(false);
26940
26824
  const [moveModalOpen, setMoveModalOpen] = (0, import_react57.useState)(false);
26941
26825
  const [conversationToMove, setConversationToMove] = (0, import_react57.useState)(null);
26942
26826
  const [renameProjectId, setRenameProjectId] = (0, import_react57.useState)(null);
@@ -27757,7 +27641,7 @@ var init_conversation_drawer = __esm({
27757
27641
  currentProjectId: conversationToMove.projectId
27758
27642
  }
27759
27643
  ),
27760
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
27644
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
27761
27645
  import_material46.Menu,
27762
27646
  {
27763
27647
  anchorEl: menuAnchorEl,
@@ -27771,20 +27655,43 @@ var init_conversation_drawer = __esm({
27771
27655
  vertical: "bottom",
27772
27656
  horizontal: "right"
27773
27657
  },
27774
- children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
27775
- import_material46.MenuItem,
27776
- {
27777
- onClick: () => {
27778
- setClearConfirmOpen(true);
27779
- handleMenuClose();
27780
- },
27781
- sx: { color: theme.palette.error.main },
27782
- children: [
27783
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_material46.ListItemIcon, { children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react14.Trash2, { size: 16, color: theme.palette.error.main }) }),
27784
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_material46.ListItemText, { children: "Clear All Conversations" })
27785
- ]
27786
- }
27787
- )
27658
+ children: [
27659
+ preferences.feedbackEnabled && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
27660
+ import_material46.MenuItem,
27661
+ {
27662
+ onClick: () => {
27663
+ setFeedbackOpen(true);
27664
+ handleMenuClose();
27665
+ },
27666
+ children: [
27667
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_material46.ListItemIcon, { children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react14.MessageSquare, { size: 16 }) }),
27668
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_material46.ListItemText, { children: "Send feedback" })
27669
+ ]
27670
+ }
27671
+ ),
27672
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
27673
+ import_material46.MenuItem,
27674
+ {
27675
+ onClick: () => {
27676
+ setClearConfirmOpen(true);
27677
+ handleMenuClose();
27678
+ },
27679
+ sx: { color: theme.palette.error.main },
27680
+ children: [
27681
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_material46.ListItemIcon, { children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react14.Trash2, { size: 16, color: theme.palette.error.main }) }),
27682
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_material46.ListItemText, { children: "Clear All Conversations" })
27683
+ ]
27684
+ }
27685
+ )
27686
+ ]
27687
+ }
27688
+ ),
27689
+ preferences.feedbackEnabled && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
27690
+ FeedbackModal,
27691
+ {
27692
+ open: feedbackOpen,
27693
+ onClose: () => setFeedbackOpen(false),
27694
+ feedbackEmail: usePackageSettingsStore.getState().settings?.feedbackEmail
27788
27695
  }
27789
27696
  ),
27790
27697
  /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
@@ -28223,7 +28130,10 @@ var init_enhanced_mobile_conversations_modal = __esm({
28223
28130
  display: "flex",
28224
28131
  flexDirection: "column",
28225
28132
  overflow: "hidden",
28226
- outline: "none"
28133
+ outline: "none",
28134
+ // Edge-to-edge PWA: the drawer surface runs under the status
28135
+ // bar (like Claude); its content starts below it.
28136
+ pt: "env(safe-area-inset-top, 0px)"
28227
28137
  },
28228
28138
  children: [
28229
28139
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
@@ -29112,6 +29022,8 @@ var init_chat_app_bar = __esm({
29112
29022
  width: "100%",
29113
29023
  px: 2,
29114
29024
  py: 1,
29025
+ // Edge-to-edge PWA: keep the pills below the status bar / notch.
29026
+ pt: "calc(8px + env(safe-area-inset-top, 0px))",
29115
29027
  display: "flex",
29116
29028
  alignItems: "center",
29117
29029
  justifyContent: "space-between",
@@ -29744,20 +29656,185 @@ var init_UnderReview = __esm({
29744
29656
  }
29745
29657
  });
29746
29658
 
29659
+ // src/components/feedback/FeedbackPulse.tsx
29660
+ var import_react61, import_material52, import_styles33, import_lucide_react16, import_jsx_runtime51, STORAGE_KEY3, COOLDOWN_DAYS, MIN_SESSION_MS, MIN_MESSAGES_SENT, CHECK_INTERVAL_MS, readLastInteraction, recordInteraction, FeedbackPulse, FeedbackPulse_default;
29661
+ var init_FeedbackPulse = __esm({
29662
+ "src/components/feedback/FeedbackPulse.tsx"() {
29663
+ "use strict";
29664
+ import_react61 = require("react");
29665
+ import_material52 = require("@mui/material");
29666
+ import_styles33 = require("@mui/material/styles");
29667
+ import_lucide_react16 = require("lucide-react");
29668
+ init_conversationStore();
29669
+ init_FeedbackModal();
29670
+ init_debugLogger();
29671
+ import_jsx_runtime51 = require("react/jsx-runtime");
29672
+ STORAGE_KEY3 = "bandit-feedback-pulse-last";
29673
+ COOLDOWN_DAYS = 14;
29674
+ MIN_SESSION_MS = 5 * 60 * 1e3;
29675
+ MIN_MESSAGES_SENT = 2;
29676
+ CHECK_INTERVAL_MS = 30 * 1e3;
29677
+ readLastInteraction = () => {
29678
+ try {
29679
+ return Number(localStorage.getItem(STORAGE_KEY3)) || 0;
29680
+ } catch {
29681
+ return 0;
29682
+ }
29683
+ };
29684
+ recordInteraction = (outcome) => {
29685
+ try {
29686
+ localStorage.setItem(STORAGE_KEY3, String(Date.now()));
29687
+ } catch {
29688
+ }
29689
+ debugLogger.info("FeedbackPulse: interaction recorded", { outcome });
29690
+ };
29691
+ FeedbackPulse = ({ isMobile, feedbackEmail }) => {
29692
+ const theme = (0, import_styles33.useTheme)();
29693
+ const [visible, setVisible] = (0, import_react61.useState)(false);
29694
+ const [thanked, setThanked] = (0, import_react61.useState)(false);
29695
+ const [modalOpen, setModalOpen] = (0, import_react61.useState)(false);
29696
+ const mountedAtRef = (0, import_react61.useRef)(Date.now());
29697
+ const baselineMessagesRef = (0, import_react61.useRef)(null);
29698
+ const totalMessages = useConversationStore(
29699
+ (s) => s.conversations.reduce((n, c) => n + c.history.length, 0)
29700
+ );
29701
+ const hydrated = useConversationStore((s) => s._hasHydrated);
29702
+ (0, import_react61.useEffect)(() => {
29703
+ if (hydrated && baselineMessagesRef.current === null) {
29704
+ baselineMessagesRef.current = totalMessages;
29705
+ }
29706
+ }, [hydrated, totalMessages]);
29707
+ (0, import_react61.useEffect)(() => {
29708
+ const cooldownMs = COOLDOWN_DAYS * 24 * 60 * 60 * 1e3;
29709
+ const forced = typeof window !== "undefined" && new URLSearchParams(window.location.search).has("feedbackPulse");
29710
+ const check = () => {
29711
+ if (visible || thanked || modalOpen) return;
29712
+ if (forced) {
29713
+ setVisible(true);
29714
+ return;
29715
+ }
29716
+ if (Date.now() - readLastInteraction() < cooldownMs) return;
29717
+ if (Date.now() - mountedAtRef.current < MIN_SESSION_MS) return;
29718
+ const baseline = baselineMessagesRef.current;
29719
+ if (baseline === null) return;
29720
+ const sentThisSession = useConversationStore.getState().conversations.reduce((n, c) => n + c.history.length, 0) - baseline;
29721
+ if (sentThisSession < MIN_MESSAGES_SENT) return;
29722
+ setVisible(true);
29723
+ };
29724
+ if (forced) check();
29725
+ const timer = setInterval(check, CHECK_INTERVAL_MS);
29726
+ return () => clearInterval(timer);
29727
+ }, [visible, thanked, modalOpen]);
29728
+ const answer = (outcome) => {
29729
+ recordInteraction(outcome);
29730
+ if (outcome === "bad") {
29731
+ setVisible(false);
29732
+ setModalOpen(true);
29733
+ return;
29734
+ }
29735
+ setThanked(true);
29736
+ setTimeout(() => {
29737
+ setVisible(false);
29738
+ setThanked(false);
29739
+ }, 1600);
29740
+ };
29741
+ const dismiss = () => {
29742
+ recordInteraction("dismissed");
29743
+ setVisible(false);
29744
+ };
29745
+ const choice = (emoji, label, outcome) => /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
29746
+ import_material52.Box,
29747
+ {
29748
+ component: "button",
29749
+ type: "button",
29750
+ onClick: () => answer(outcome),
29751
+ sx: {
29752
+ font: "inherit",
29753
+ display: "flex",
29754
+ flexDirection: "column",
29755
+ alignItems: "center",
29756
+ gap: 0.25,
29757
+ px: 1.5,
29758
+ py: 0.75,
29759
+ border: "none",
29760
+ borderRadius: 2,
29761
+ cursor: "pointer",
29762
+ bgcolor: "transparent",
29763
+ color: theme.palette.text.secondary,
29764
+ transition: "background-color 0.15s ease, transform 0.1s ease",
29765
+ "&:hover": {
29766
+ bgcolor: (0, import_styles33.alpha)(theme.palette.text.primary, 0.06),
29767
+ color: theme.palette.text.primary
29768
+ },
29769
+ "&:active": { transform: "scale(0.96)" }
29770
+ },
29771
+ children: [
29772
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material52.Box, { component: "span", sx: { fontSize: "1.3rem", lineHeight: 1 }, children: emoji }),
29773
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material52.Typography, { variant: "caption", sx: { fontWeight: 600 }, children: label })
29774
+ ]
29775
+ }
29776
+ );
29777
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
29778
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material52.Slide, { direction: isMobile ? "down" : "up", in: visible, mountOnEnter: true, unmountOnExit: true, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
29779
+ import_material52.Paper,
29780
+ {
29781
+ elevation: 0,
29782
+ sx: {
29783
+ position: "fixed",
29784
+ zIndex: 1350,
29785
+ ...isMobile ? {
29786
+ top: `calc(${theme.spacing(8)} + env(safe-area-inset-top, 0px))`,
29787
+ left: "50%",
29788
+ transform: "translateX(-50%) !important",
29789
+ width: "min(92vw, 360px)"
29790
+ } : { bottom: 24, right: 24, width: 320 },
29791
+ p: 1.5,
29792
+ borderRadius: 3,
29793
+ border: `1px solid ${theme.palette.divider}`,
29794
+ bgcolor: theme.palette.background.paper,
29795
+ boxShadow: `0 12px 40px ${(0, import_styles33.alpha)(theme.palette.common.black, theme.palette.mode === "dark" ? 0.5 : 0.18)}`
29796
+ },
29797
+ children: thanked ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material52.Typography, { sx: { textAlign: "center", py: 1.5, fontWeight: 600 }, children: "Thanks for the feedback! \u{1F64C}" }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
29798
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material52.Box, { sx: { display: "flex", alignItems: "center", mb: 0.5 }, children: [
29799
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material52.Typography, { variant: "body2", sx: { fontWeight: 600, flex: 1 }, children: "How's Bandit doing?" }),
29800
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material52.IconButton, { size: "small", onClick: dismiss, "aria-label": "Dismiss feedback prompt", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react16.X, { size: 16 }) })
29801
+ ] }),
29802
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material52.Box, { sx: { display: "flex", justifyContent: "space-evenly" }, children: [
29803
+ choice("\u{1F60A}", "Good", "good"),
29804
+ choice("\u{1F610}", "Fine", "fine"),
29805
+ choice("\u{1F641}", "Bad", "bad")
29806
+ ] })
29807
+ ] })
29808
+ }
29809
+ ) }),
29810
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
29811
+ FeedbackModal,
29812
+ {
29813
+ open: modalOpen,
29814
+ onClose: () => setModalOpen(false),
29815
+ feedbackEmail
29816
+ }
29817
+ )
29818
+ ] });
29819
+ };
29820
+ FeedbackPulse_default = FeedbackPulse;
29821
+ }
29822
+ });
29823
+
29747
29824
  // src/components/ConnectionStatus.tsx
29748
- var import_material52, import_jsx_runtime51, ConnectionStatus;
29825
+ var import_material53, import_jsx_runtime52, ConnectionStatus;
29749
29826
  var init_ConnectionStatus = __esm({
29750
29827
  "src/components/ConnectionStatus.tsx"() {
29751
29828
  "use strict";
29752
- import_material52 = require("@mui/material");
29829
+ import_material53 = require("@mui/material");
29753
29830
  init_useNetworkStatus();
29754
29831
  init_lucide_icons();
29755
- import_jsx_runtime51 = require("react/jsx-runtime");
29832
+ import_jsx_runtime52 = require("react/jsx-runtime");
29756
29833
  ConnectionStatus = ({
29757
29834
  showWhenGood = false,
29758
29835
  position = "top"
29759
29836
  }) => {
29760
- const theme = (0, import_material52.useTheme)();
29837
+ const theme = (0, import_material53.useTheme)();
29761
29838
  const { isOnline, connectionQuality, isSlowConnection } = useNetworkStatus();
29762
29839
  if (connectionQuality === "fast" && !showWhenGood) {
29763
29840
  return null;
@@ -29766,28 +29843,28 @@ var init_ConnectionStatus = __esm({
29766
29843
  switch (connectionQuality) {
29767
29844
  case "offline":
29768
29845
  return {
29769
- icon: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(WifiOffIcon, { sx: { fontSize: 16 } }),
29846
+ icon: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(WifiOffIcon, { sx: { fontSize: 16 } }),
29770
29847
  label: "Offline",
29771
29848
  color: "error",
29772
29849
  severity: "high"
29773
29850
  };
29774
29851
  case "slow":
29775
29852
  return {
29776
- icon: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(SignalWifi2BarIcon, { sx: { fontSize: 16 } }),
29853
+ icon: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SignalWifi2BarIcon, { sx: { fontSize: 16 } }),
29777
29854
  label: "Slow connection",
29778
29855
  color: "warning",
29779
29856
  severity: "medium"
29780
29857
  };
29781
29858
  case "fast":
29782
29859
  return {
29783
- icon: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(WifiIcon, { sx: { fontSize: 16 } }),
29860
+ icon: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(WifiIcon, { sx: { fontSize: 16 } }),
29784
29861
  label: "Connected",
29785
29862
  color: "success",
29786
29863
  severity: "low"
29787
29864
  };
29788
29865
  default:
29789
29866
  return {
29790
- icon: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(WifiIcon, { sx: { fontSize: 16 } }),
29867
+ icon: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(WifiIcon, { sx: { fontSize: 16 } }),
29791
29868
  label: "Unknown",
29792
29869
  color: "default",
29793
29870
  severity: "low"
@@ -29795,8 +29872,8 @@ var init_ConnectionStatus = __esm({
29795
29872
  }
29796
29873
  };
29797
29874
  const config = getStatusConfig();
29798
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
29799
- import_material52.Box,
29875
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
29876
+ import_material53.Box,
29800
29877
  {
29801
29878
  sx: {
29802
29879
  position: "fixed",
@@ -29811,8 +29888,8 @@ var init_ConnectionStatus = __esm({
29811
29888
  "100%": { opacity: 1 }
29812
29889
  }
29813
29890
  },
29814
- children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
29815
- import_material52.Chip,
29891
+ children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
29892
+ import_material53.Chip,
29816
29893
  {
29817
29894
  icon: config.icon,
29818
29895
  label: config.label,
@@ -29837,11 +29914,11 @@ var init_ConnectionStatus = __esm({
29837
29914
  });
29838
29915
 
29839
29916
  // src/hooks/useVoiceMode.ts
29840
- var import_react61, RMS_BASELINE, RMS_NORMALIZER, computeRms, pickSupportedMimeType, useVoiceMode;
29917
+ var import_react62, RMS_BASELINE, RMS_NORMALIZER, computeRms, pickSupportedMimeType, useVoiceMode;
29841
29918
  var init_useVoiceMode = __esm({
29842
29919
  "src/hooks/useVoiceMode.ts"() {
29843
29920
  "use strict";
29844
- import_react61 = require("react");
29921
+ import_react62 = require("react");
29845
29922
  init_stt_client();
29846
29923
  init_debugLogger();
29847
29924
  init_voiceModeStore();
@@ -29874,11 +29951,11 @@ var init_useVoiceMode = __esm({
29874
29951
  const setError = useVoiceModeStore((state) => state.setError);
29875
29952
  const resetTransientState = useVoiceModeStore((state) => state.resetTransientState);
29876
29953
  const setLastTranscript = useVoiceModeStore((state) => state.setLastTranscript);
29877
- const configRef = (0, import_react61.useRef)(config);
29878
- (0, import_react61.useEffect)(() => {
29954
+ const configRef = (0, import_react62.useRef)(config);
29955
+ (0, import_react62.useEffect)(() => {
29879
29956
  configRef.current = config;
29880
29957
  }, [config]);
29881
- (0, import_react61.useEffect)(() => {
29958
+ (0, import_react62.useEffect)(() => {
29882
29959
  if (!enabled) {
29883
29960
  return () => void 0;
29884
29961
  }
@@ -30139,15 +30216,15 @@ var chat_exports = {};
30139
30216
  __export(chat_exports, {
30140
30217
  default: () => chat_default
30141
30218
  });
30142
- var import_react62, import_material53, import_styles33, import_react_router_dom5, import_jsx_runtime52, ChatContent, Chat, chat_default;
30219
+ var import_react63, import_material54, import_styles34, import_react_router_dom5, import_jsx_runtime53, ChatContent, Chat, chat_default;
30143
30220
  var init_chat2 = __esm({
30144
30221
  "src/chat/chat.tsx"() {
30145
30222
  "use strict";
30146
- import_react62 = require("react");
30223
+ import_react63 = require("react");
30147
30224
  init_custom_logo();
30148
30225
  init_indexedDBService();
30149
- import_material53 = require("@mui/material");
30150
- import_styles33 = require("@mui/material/styles");
30226
+ import_material54 = require("@mui/material");
30227
+ import_styles34 = require("@mui/material/styles");
30151
30228
  init_aiQueryStore();
30152
30229
  init_modelStore();
30153
30230
  init_canvasStore();
@@ -30178,14 +30255,14 @@ var init_chat2 = __esm({
30178
30255
  init_preferencesStore();
30179
30256
  init_debugLogger();
30180
30257
  init_streaming_tts();
30181
- init_FeedbackButton();
30258
+ init_FeedbackPulse();
30182
30259
  init_useNotificationService();
30183
30260
  init_ConnectionStatus();
30184
30261
  init_useVoiceMode();
30185
30262
  init_voiceModeStore();
30186
30263
  init_ttsSanitizer();
30187
30264
  init_FeatureFlagContext();
30188
- import_jsx_runtime52 = require("react/jsx-runtime");
30265
+ import_jsx_runtime53 = require("react/jsx-runtime");
30189
30266
  ChatContent = () => {
30190
30267
  const packageSettings = usePackageSettingsStore((state) => state.settings);
30191
30268
  const UnderReviewView = packageSettings?.components?.UnderReview ?? UnderReview_default;
@@ -30194,13 +30271,13 @@ var init_chat2 = __esm({
30194
30271
  const ossMode = isOSSMode() || !packageSettings?.featureFlags?.subscriptionType;
30195
30272
  const playgroundBypassAccess = packageSettings?.playgroundBypassAuth || typeof window !== "undefined" && window.location.pathname.includes("/playground");
30196
30273
  const notificationService2 = useNotificationService();
30197
- const [selectedTheme, setSelectedTheme] = (0, import_react62.useState)(null);
30198
- const [themeLoading, setThemeLoading] = (0, import_react62.useState)(true);
30274
+ const [selectedTheme, setSelectedTheme] = (0, import_react63.useState)(null);
30275
+ const [themeLoading, setThemeLoading] = (0, import_react63.useState)(true);
30199
30276
  const token = authenticationService.getToken();
30200
30277
  const claims = token ? authenticationService.parseJwtClaims(token) : null;
30201
30278
  const baseTheme = themeMap_default[selectedTheme ?? "bandit-dark"] || banditDarkTheme;
30202
- const banditTheme = (0, import_react62.useMemo)(() => {
30203
- return (0, import_styles33.createTheme)(baseTheme, {
30279
+ const banditTheme = (0, import_react63.useMemo)(() => {
30280
+ return (0, import_styles34.createTheme)(baseTheme, {
30204
30281
  components: {
30205
30282
  MuiInputBase: {
30206
30283
  styleOverrides: {
@@ -30247,12 +30324,12 @@ var init_chat2 = __esm({
30247
30324
  } = useVoiceStore();
30248
30325
  const isVoiceModeEnabled = useVoiceModeStore((state) => state.enabled);
30249
30326
  const canvasOpen = useCanvasStore((state) => state.open);
30250
- const previousVoiceModeEnabledRef = (0, import_react62.useRef)(isVoiceModeEnabled);
30251
- const historyRef = (0, import_react62.useRef)(history);
30252
- (0, import_react62.useEffect)(() => {
30327
+ const previousVoiceModeEnabledRef = (0, import_react63.useRef)(isVoiceModeEnabled);
30328
+ const historyRef = (0, import_react63.useRef)(history);
30329
+ (0, import_react63.useEffect)(() => {
30253
30330
  historyRef.current = history;
30254
30331
  }, [history]);
30255
- (0, import_react62.useEffect)(() => {
30332
+ (0, import_react63.useEffect)(() => {
30256
30333
  if (!hydrated) return;
30257
30334
  const params = new URLSearchParams(window.location.search);
30258
30335
  const title = params.get("title") || "";
@@ -30268,7 +30345,7 @@ var init_chat2 = __esm({
30268
30345
  stop: ttsStop,
30269
30346
  isAvailable: isTTSAvailable
30270
30347
  } = useTTS();
30271
- (0, import_react62.useEffect)(() => {
30348
+ (0, import_react63.useEffect)(() => {
30272
30349
  const timer = setTimeout(() => {
30273
30350
  const isAuthenticated = authenticationService.isAuthenticated();
30274
30351
  if (!initialized || availableVoices.length === 0) {
@@ -30282,7 +30359,7 @@ var init_chat2 = __esm({
30282
30359
  }, 500);
30283
30360
  return () => clearTimeout(timer);
30284
30361
  }, [initialized, availableVoices.length, loadVoicesFromAPI, token]);
30285
- (0, import_react62.useEffect)(() => {
30362
+ (0, import_react63.useEffect)(() => {
30286
30363
  const isAuthenticated = authenticationService.isAuthenticated();
30287
30364
  if (packageSettings?.gatewayApiUrl && availableVoices.length === 0 && !initialized) {
30288
30365
  if (token && isAuthenticated) {
@@ -30294,17 +30371,17 @@ var init_chat2 = __esm({
30294
30371
  }
30295
30372
  }, [packageSettings?.gatewayApiUrl, availableVoices.length, initialized, loadVoicesFromAPI, token]);
30296
30373
  const provider = useAIProviderStore((state) => state.provider);
30297
- const inputRef = (0, import_react62.useRef)(null);
30298
- const [pastedImages, setPastedImages] = (0, import_react62.useState)([]);
30299
- const inputContainerRef = (0, import_react62.useRef)(null);
30300
- const [inputHeight, setInputHeight] = (0, import_react62.useState)(80);
30301
- const [isSubmitting, setIsSubmitting] = (0, import_react62.useState)(false);
30302
- const [pendingMessage, setPendingMessage] = (0, import_react62.useState)(null);
30374
+ const inputRef = (0, import_react63.useRef)(null);
30375
+ const [pastedImages, setPastedImages] = (0, import_react63.useState)([]);
30376
+ const inputContainerRef = (0, import_react63.useRef)(null);
30377
+ const [inputHeight, setInputHeight] = (0, import_react63.useState)(80);
30378
+ const [isSubmitting, setIsSubmitting] = (0, import_react63.useState)(false);
30379
+ const [pendingMessage, setPendingMessage] = (0, import_react63.useState)(null);
30303
30380
  const { conversations, currentId, _hasHydrated, hydrate, toggleIncognito } = useConversationStore();
30304
30381
  const isTemporaryChat = Boolean(conversations.find((c) => c.id === currentId)?.incognito);
30305
- const [isMobile, setIsMobile] = (0, import_react62.useState)(false);
30306
- const [drawerOpen, setDrawerOpen] = (0, import_react62.useState)(false);
30307
- const [mobileConversationsOpen, setMobileConversationsOpen] = (0, import_react62.useState)(false);
30382
+ const [isMobile, setIsMobile] = (0, import_react63.useState)(false);
30383
+ const [drawerOpen, setDrawerOpen] = (0, import_react63.useState)(false);
30384
+ const [mobileConversationsOpen, setMobileConversationsOpen] = (0, import_react63.useState)(false);
30308
30385
  const { generateName } = useConversationNameGenerator();
30309
30386
  const { preferences } = usePreferencesStore();
30310
30387
  const { containerRef: chatContainerRef, targetRef: scrollTargetRef, scrollToBottom, getScrollState } = useAutoScroll({
@@ -30316,27 +30393,27 @@ var init_chat2 = __esm({
30316
30393
  const chatContainerEl = chatContainerRef.current;
30317
30394
  const scrollTargetEl = scrollTargetRef.current;
30318
30395
  const { isSlowConnection, connectionQuality, trackRequestStart, trackRequestEnd } = useNetworkStatus();
30319
- const [showScrollToBottom, setShowScrollToBottom] = (0, import_react62.useState)(false);
30320
- const [streamBuffer, setStreamBuffer] = (0, import_react62.useState)("");
30321
- const [responseStarted, setResponseStarted] = (0, import_react62.useState)(false);
30322
- const [isStreaming, setIsStreaming] = (0, import_react62.useState)(false);
30323
- const [isThinking, setIsThinking] = (0, import_react62.useState)(false);
30396
+ const [showScrollToBottom, setShowScrollToBottom] = (0, import_react63.useState)(false);
30397
+ const [streamBuffer, setStreamBuffer] = (0, import_react63.useState)("");
30398
+ const [responseStarted, setResponseStarted] = (0, import_react63.useState)(false);
30399
+ const [isStreaming, setIsStreaming] = (0, import_react63.useState)(false);
30400
+ const [isThinking, setIsThinking] = (0, import_react63.useState)(false);
30324
30401
  const initialLogoState = history.length === 0;
30325
- const [logoVisible, setLogoVisible] = (0, import_react62.useState)(initialLogoState);
30326
- const [logoShouldRender, setLogoShouldRender] = (0, import_react62.useState)(initialLogoState);
30327
- const streamingGraceUntilRef = (0, import_react62.useRef)(0);
30402
+ const [logoVisible, setLogoVisible] = (0, import_react63.useState)(initialLogoState);
30403
+ const [logoShouldRender, setLogoShouldRender] = (0, import_react63.useState)(initialLogoState);
30404
+ const streamingGraceUntilRef = (0, import_react63.useRef)(0);
30328
30405
  const GRACE_MS = 450;
30329
30406
  const GRACE_OFFSET_DESKTOP = 28;
30330
30407
  const GRACE_OFFSET_MOBILE = 20;
30331
- const followStreamRef = (0, import_react62.useRef)(true);
30332
- const lastSpokenResponseRef = (0, import_react62.useRef)(null);
30333
- const previousConversationIdRef = (0, import_react62.useRef)(null);
30334
- const logoFadeTimeoutRef = (0, import_react62.useRef)(null);
30335
- const [branding, setBranding] = (0, import_react62.useState)(null);
30336
- const [brandingLoading, setBrandingLoading] = (0, import_react62.useState)(true);
30337
- const isBrandingLoadInProgressRef = (0, import_react62.useRef)(false);
30408
+ const followStreamRef = (0, import_react63.useRef)(true);
30409
+ const lastSpokenResponseRef = (0, import_react63.useRef)(null);
30410
+ const previousConversationIdRef = (0, import_react63.useRef)(null);
30411
+ const logoFadeTimeoutRef = (0, import_react63.useRef)(null);
30412
+ const [branding, setBranding] = (0, import_react63.useState)(null);
30413
+ const [brandingLoading, setBrandingLoading] = (0, import_react63.useState)(true);
30414
+ const isBrandingLoadInProgressRef = (0, import_react63.useRef)(false);
30338
30415
  const logoOnly = history.length === 0 && !brandingLoading;
30339
- (0, import_react62.useEffect)(() => {
30416
+ (0, import_react63.useEffect)(() => {
30340
30417
  const isEmptyConversation = (history?.length ?? 0) === 0;
30341
30418
  const isSending = Boolean(pendingMessage);
30342
30419
  const shouldShowLogo = isEmptyConversation && !isSending;
@@ -30366,7 +30443,7 @@ var init_chat2 = __esm({
30366
30443
  }, 500);
30367
30444
  }
30368
30445
  }, [history, pendingMessage]);
30369
- (0, import_react62.useEffect)(() => {
30446
+ (0, import_react63.useEffect)(() => {
30370
30447
  if (!brandingLoading && !themeLoading) {
30371
30448
  return;
30372
30449
  }
@@ -30382,18 +30459,18 @@ var init_chat2 = __esm({
30382
30459
  }, 2500);
30383
30460
  return () => window.clearTimeout(timeoutId);
30384
30461
  }, [brandingLoading, themeLoading, selectedTheme]);
30385
- (0, import_react62.useEffect)(() => () => {
30462
+ (0, import_react63.useEffect)(() => () => {
30386
30463
  if (logoFadeTimeoutRef.current) {
30387
30464
  window.clearTimeout(logoFadeTimeoutRef.current);
30388
30465
  logoFadeTimeoutRef.current = null;
30389
30466
  }
30390
30467
  }, []);
30391
- (0, import_react62.useEffect)(() => {
30468
+ (0, import_react63.useEffect)(() => {
30392
30469
  if (isStreaming && streamBuffer.trim() === "") {
30393
30470
  streamingGraceUntilRef.current = Date.now() + GRACE_MS;
30394
30471
  }
30395
30472
  }, [isStreaming, streamBuffer]);
30396
- (0, import_react62.useEffect)(() => {
30473
+ (0, import_react63.useEffect)(() => {
30397
30474
  if (!isStreaming) return;
30398
30475
  const container = chatContainerRef.current;
30399
30476
  if (!container) return;
@@ -30404,13 +30481,13 @@ var init_chat2 = __esm({
30404
30481
  container.scrollTo({ top: targetTop, behavior: "smooth" });
30405
30482
  }
30406
30483
  }, [streamBuffer, isStreaming, isMobile, chatContainerRef]);
30407
- (0, import_react62.useEffect)(() => {
30484
+ (0, import_react63.useEffect)(() => {
30408
30485
  if (!_hasHydrated) {
30409
30486
  debugLogger.info("Chat component triggering conversation store hydration");
30410
30487
  hydrate();
30411
30488
  }
30412
30489
  }, [_hasHydrated, hydrate]);
30413
- (0, import_react62.useEffect)(() => {
30490
+ (0, import_react63.useEffect)(() => {
30414
30491
  const loadBrandingAndTheme = async () => {
30415
30492
  if (isBrandingLoadInProgressRef.current) {
30416
30493
  debugLogger.warn("Branding loading already in progress, skipping");
@@ -30599,7 +30676,7 @@ var init_chat2 = __esm({
30599
30676
  window.removeEventListener("bandit-theme-changed", handleThemeChange);
30600
30677
  };
30601
30678
  }, []);
30602
- (0, import_react62.useEffect)(() => {
30679
+ (0, import_react63.useEffect)(() => {
30603
30680
  if (!chatContainerEl) return;
30604
30681
  const blurInputOnTouchScroll = () => {
30605
30682
  if (document.activeElement === inputRef.current) inputRef.current?.blur();
@@ -30607,13 +30684,13 @@ var init_chat2 = __esm({
30607
30684
  chatContainerEl.addEventListener("touchmove", blurInputOnTouchScroll, { passive: true });
30608
30685
  return () => chatContainerEl.removeEventListener("touchmove", blurInputOnTouchScroll);
30609
30686
  }, [chatContainerEl]);
30610
- (0, import_react62.useEffect)(() => {
30687
+ (0, import_react63.useEffect)(() => {
30611
30688
  const handleResize = () => setIsMobile(window.innerWidth <= 768);
30612
30689
  handleResize();
30613
30690
  window.addEventListener("resize", handleResize);
30614
30691
  return () => window.removeEventListener("resize", handleResize);
30615
30692
  }, []);
30616
- (0, import_react62.useEffect)(() => {
30693
+ (0, import_react63.useEffect)(() => {
30617
30694
  const setViewportHeight = () => {
30618
30695
  document.documentElement.style.setProperty(
30619
30696
  "--vh",
@@ -30624,7 +30701,7 @@ var init_chat2 = __esm({
30624
30701
  window.addEventListener("resize", setViewportHeight);
30625
30702
  return () => window.removeEventListener("resize", setViewportHeight);
30626
30703
  }, []);
30627
- (0, import_react62.useEffect)(() => {
30704
+ (0, import_react63.useEffect)(() => {
30628
30705
  if (!chatContainerEl) return;
30629
30706
  let rafId = null;
30630
30707
  const update = () => {
@@ -30643,7 +30720,7 @@ var init_chat2 = __esm({
30643
30720
  chatContainerEl.removeEventListener(SCROLL_STATE_CHANGED_EVENT, update);
30644
30721
  };
30645
30722
  }, [chatContainerEl, getScrollState]);
30646
- (0, import_react62.useEffect)(() => {
30723
+ (0, import_react63.useEffect)(() => {
30647
30724
  if (!chatContainerEl) return;
30648
30725
  let observer = null;
30649
30726
  let rafId = null;
@@ -30678,7 +30755,7 @@ var init_chat2 = __esm({
30678
30755
  if (observer) observer.disconnect();
30679
30756
  };
30680
30757
  }, [chatContainerEl, scrollTargetEl, scrollTargetRef, getScrollState, inputHeight, history.length]);
30681
- (0, import_react62.useEffect)(() => {
30758
+ (0, import_react63.useEffect)(() => {
30682
30759
  const isTransitioning = isStreaming || streamBuffer.trim() === "";
30683
30760
  const delay = isTransitioning ? 400 : 100;
30684
30761
  const timer = setTimeout(() => {
@@ -30687,7 +30764,7 @@ var init_chat2 = __esm({
30687
30764
  }, delay);
30688
30765
  return () => clearTimeout(timer);
30689
30766
  }, [history, streamBuffer, getScrollState, isStreaming]);
30690
- (0, import_react62.useLayoutEffect)(() => {
30767
+ (0, import_react63.useLayoutEffect)(() => {
30691
30768
  const scrollState = getScrollState();
30692
30769
  const now = Date.now();
30693
30770
  if (isStreaming && scrollState.shouldAutoScroll && followStreamRef.current) {
@@ -30721,7 +30798,7 @@ var init_chat2 = __esm({
30721
30798
  return () => clearTimeout(scrollTimer);
30722
30799
  }
30723
30800
  }, [history, isStreaming, scrollToBottom, getScrollState, isMobile, chatContainerRef]);
30724
- (0, import_react62.useEffect)(() => {
30801
+ (0, import_react63.useEffect)(() => {
30725
30802
  const observer = new ResizeObserver(() => {
30726
30803
  if (inputContainerRef.current)
30727
30804
  setInputHeight(inputContainerRef.current.offsetHeight);
@@ -30732,7 +30809,7 @@ var init_chat2 = __esm({
30732
30809
  }
30733
30810
  return () => observer.disconnect();
30734
30811
  }, []);
30735
- (0, import_react62.useEffect)(() => {
30812
+ (0, import_react63.useEffect)(() => {
30736
30813
  if (!hydrated || !_hasHydrated) return;
30737
30814
  if (currentId === null) {
30738
30815
  useAIQueryStore.setState({ history: [] });
@@ -30781,7 +30858,7 @@ var init_chat2 = __esm({
30781
30858
  setResponse,
30782
30859
  setComponentStatus
30783
30860
  ]);
30784
- (0, import_react62.useEffect)(() => {
30861
+ (0, import_react63.useEffect)(() => {
30785
30862
  debugLogger.info("Chat component conversation state", {
30786
30863
  hasHydrated: _hasHydrated,
30787
30864
  conversationCount: conversations.length,
@@ -30790,7 +30867,7 @@ var init_chat2 = __esm({
30790
30867
  storeState: "main-chat"
30791
30868
  });
30792
30869
  }, [_hasHydrated, conversations, currentId]);
30793
- (0, import_react62.useEffect)(() => {
30870
+ (0, import_react63.useEffect)(() => {
30794
30871
  if (!_hasHydrated || !chatContainerEl) return;
30795
30872
  let rafId = null;
30796
30873
  const sync = () => {
@@ -30825,7 +30902,7 @@ var init_chat2 = __esm({
30825
30902
  notificationService2?.handleHttpError(error);
30826
30903
  }
30827
30904
  });
30828
- const handleStop = (0, import_react62.useCallback)(() => {
30905
+ const handleStop = (0, import_react63.useCallback)(() => {
30829
30906
  try {
30830
30907
  aiProvider.cancel();
30831
30908
  } catch (error) {
@@ -30834,7 +30911,7 @@ var init_chat2 = __esm({
30834
30911
  });
30835
30912
  }
30836
30913
  }, [aiProvider]);
30837
- const handleVoiceInterrupt = (0, import_react62.useCallback)(() => {
30914
+ const handleVoiceInterrupt = (0, import_react63.useCallback)(() => {
30838
30915
  try {
30839
30916
  ttsStop();
30840
30917
  } catch (error) {
@@ -30853,7 +30930,7 @@ var init_chat2 = __esm({
30853
30930
  handleStop();
30854
30931
  }
30855
30932
  }, [ttsStop, isStreaming, handleStop]);
30856
- const handleSend = (0, import_react62.useCallback)(
30933
+ const handleSend = (0, import_react63.useCallback)(
30857
30934
  (question, images, displayQuestion) => {
30858
30935
  const requestStartTime = trackRequestStart();
30859
30936
  const questionForDisplay = displayQuestion || question;
@@ -30963,7 +31040,7 @@ var init_chat2 = __esm({
30963
31040
  trackRequestStart
30964
31041
  ]
30965
31042
  );
30966
- const handleVoiceTranscription = (0, import_react62.useCallback)(
31043
+ const handleVoiceTranscription = (0, import_react63.useCallback)(
30967
31044
  (text) => {
30968
31045
  const cleaned = text.trim();
30969
31046
  if (!cleaned) {
@@ -30980,7 +31057,7 @@ var init_chat2 = __esm({
30980
31057
  onInterrupt: handleVoiceInterrupt,
30981
31058
  onError: (message) => notificationService2?.showError?.(message)
30982
31059
  });
30983
- (0, import_react62.useEffect)(() => {
31060
+ (0, import_react63.useEffect)(() => {
30984
31061
  const previouslyEnabled = previousVoiceModeEnabledRef.current;
30985
31062
  previousVoiceModeEnabledRef.current = isVoiceModeEnabled;
30986
31063
  if (!previouslyEnabled && isVoiceModeEnabled) {
@@ -31005,7 +31082,7 @@ var init_chat2 = __esm({
31005
31082
  }
31006
31083
  }
31007
31084
  }, [isVoiceModeEnabled, ttsStop]);
31008
- (0, import_react62.useEffect)(() => {
31085
+ (0, import_react63.useEffect)(() => {
31009
31086
  if (!isVoiceModeEnabled || !isStreaming) {
31010
31087
  return;
31011
31088
  }
@@ -31025,7 +31102,7 @@ var init_chat2 = __esm({
31025
31102
  }
31026
31103
  lastSpokenResponseRef.current = null;
31027
31104
  }, [isStreaming, isVoiceModeEnabled, ttsStop]);
31028
- (0, import_react62.useEffect)(() => {
31105
+ (0, import_react63.useEffect)(() => {
31029
31106
  if (!isVoiceModeEnabled) {
31030
31107
  lastSpokenResponseRef.current = null;
31031
31108
  return;
@@ -31066,13 +31143,13 @@ var init_chat2 = __esm({
31066
31143
  cancelled = true;
31067
31144
  };
31068
31145
  }, [history, isStreaming, isVoiceModeEnabled, isTTSAvailable, ttsSpeak]);
31069
- const handleModelChange = (0, import_react62.useCallback)(
31146
+ const handleModelChange = (0, import_react63.useCallback)(
31070
31147
  (modelId) => {
31071
31148
  setSelectedModel(modelId);
31072
31149
  },
31073
31150
  [setSelectedModel]
31074
31151
  );
31075
- const handleVoiceChange = (0, import_react62.useCallback)(async (voiceId) => {
31152
+ const handleVoiceChange = (0, import_react63.useCallback)(async (voiceId) => {
31076
31153
  ttsStop();
31077
31154
  stopTTS();
31078
31155
  setSelectedVoice(voiceId);
@@ -31105,10 +31182,10 @@ var init_chat2 = __esm({
31105
31182
  }
31106
31183
  };
31107
31184
  if (!hydrated || brandingLoading || themeLoading) {
31108
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_material53.ThemeProvider, { theme: banditTheme, children: [
31109
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_material53.CssBaseline, {}),
31110
- /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
31111
- import_material53.Box,
31185
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_material54.ThemeProvider, { theme: banditTheme, children: [
31186
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.CssBaseline, {}),
31187
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
31188
+ import_material54.Box,
31112
31189
  {
31113
31190
  sx: (theme) => ({
31114
31191
  minHeight: "100dvh",
@@ -31121,8 +31198,8 @@ var init_chat2 = __esm({
31121
31198
  color: theme.palette.text.primary
31122
31199
  }),
31123
31200
  children: [
31124
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_material53.CircularProgress, { size: 32, thickness: 4 }),
31125
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_material53.Typography, { variant: "body2", color: "text.secondary", children: "Preparing your workspace..." })
31201
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.CircularProgress, { size: 32, thickness: 4 }),
31202
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.Typography, { variant: "body2", color: "text.secondary", children: "Preparing your workspace..." })
31126
31203
  ]
31127
31204
  }
31128
31205
  )
@@ -31130,15 +31207,15 @@ var init_chat2 = __esm({
31130
31207
  }
31131
31208
  const userHasAccess = playgroundBypassAccess || ossMode || claims?.roles?.includes("super-user") || claims?.roles?.includes("admin");
31132
31209
  if (!userHasAccess) {
31133
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_material53.ThemeProvider, { theme: banditTheme, children: [
31134
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_material53.CssBaseline, {}),
31135
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(UnderReviewView, {})
31210
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_material54.ThemeProvider, { theme: banditTheme, children: [
31211
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.CssBaseline, {}),
31212
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(UnderReviewView, {})
31136
31213
  ] });
31137
31214
  }
31138
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_material53.ThemeProvider, { theme: banditTheme, children: [
31139
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_material53.CssBaseline, {}),
31140
- /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
31141
- import_material53.Box,
31215
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_material54.ThemeProvider, { theme: banditTheme, children: [
31216
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.CssBaseline, {}),
31217
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
31218
+ import_material54.Box,
31142
31219
  {
31143
31220
  sx: (theme) => ({
31144
31221
  display: "flex",
@@ -31167,7 +31244,7 @@ var init_chat2 = __esm({
31167
31244
  transition: "left 0.3s ease-in-out, width 0.3s ease-in-out, transform 0.3s ease-in-out, border-radius 0.3s ease-in-out"
31168
31245
  }),
31169
31246
  children: [
31170
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31247
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
31171
31248
  chat_app_bar_default,
31172
31249
  {
31173
31250
  availableModels,
@@ -31181,9 +31258,9 @@ var init_chat2 = __esm({
31181
31258
  onMobileConversationsOpenChange: setMobileConversationsOpen
31182
31259
  }
31183
31260
  ),
31184
- isTemporaryChat && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
31185
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31186
- import_material53.Box,
31261
+ isTemporaryChat && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, { children: [
31262
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
31263
+ import_material54.Box,
31187
31264
  {
31188
31265
  sx: (theme) => ({
31189
31266
  position: "absolute",
@@ -31195,8 +31272,8 @@ var init_chat2 = __esm({
31195
31272
  })
31196
31273
  }
31197
31274
  ),
31198
- /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
31199
- import_material53.Box,
31275
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
31276
+ import_material54.Box,
31200
31277
  {
31201
31278
  sx: (theme) => ({
31202
31279
  position: "absolute",
@@ -31220,10 +31297,10 @@ var init_chat2 = __esm({
31220
31297
  whiteSpace: "nowrap"
31221
31298
  }),
31222
31299
  children: [
31223
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_material53.Box, { component: "span", "aria-hidden": true, sx: { fontSize: "0.9rem", lineHeight: 1 }, children: "\u{1F47B}" }),
31300
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.Box, { component: "span", "aria-hidden": true, sx: { fontSize: "0.9rem", lineHeight: 1 }, children: "\u{1F47B}" }),
31224
31301
  "Temporary chat",
31225
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31226
- import_material53.Box,
31302
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
31303
+ import_material54.Box,
31227
31304
  {
31228
31305
  component: "button",
31229
31306
  type: "button",
@@ -31257,8 +31334,8 @@ var init_chat2 = __esm({
31257
31334
  }
31258
31335
  )
31259
31336
  ] }),
31260
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31261
- import_material53.Box,
31337
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
31338
+ import_material54.Box,
31262
31339
  {
31263
31340
  ref: chatContainerRef,
31264
31341
  sx: {
@@ -31278,8 +31355,8 @@ var init_chat2 = __esm({
31278
31355
  msOverflowStyle: "none",
31279
31356
  "&::-webkit-scrollbar": { display: "none" }
31280
31357
  },
31281
- children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
31282
- import_material53.Box,
31358
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
31359
+ import_material54.Box,
31283
31360
  {
31284
31361
  sx: {
31285
31362
  width: "100%",
@@ -31292,8 +31369,8 @@ var init_chat2 = __esm({
31292
31369
  logoShouldRender && !brandingLoading && (() => {
31293
31370
  const headerMode = branding?.headerMode ?? "logo";
31294
31371
  if (headerMode === "minimal") {
31295
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31296
- import_material53.Box,
31372
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
31373
+ import_material54.Box,
31297
31374
  {
31298
31375
  sx: (theme) => ({
31299
31376
  textAlign: "center",
@@ -31304,13 +31381,13 @@ var init_chat2 = __esm({
31304
31381
  transition: "opacity 0.5s ease",
31305
31382
  color: theme.palette.text.primary
31306
31383
  }),
31307
- children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_material53.Typography, { sx: { fontWeight: 500, fontSize: { xs: "1.5rem", md: "1.9rem" }, lineHeight: 1.2 }, children: "What can I help with?" })
31384
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.Typography, { sx: { fontWeight: 500, fontSize: { xs: "1.5rem", md: "1.9rem" }, lineHeight: 1.2 }, children: "What can I help with?" })
31308
31385
  }
31309
31386
  );
31310
31387
  }
31311
31388
  if (headerMode === "text") {
31312
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31313
- import_material53.Box,
31389
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
31390
+ import_material54.Box,
31314
31391
  {
31315
31392
  sx: (theme) => ({
31316
31393
  textAlign: "center",
@@ -31321,14 +31398,14 @@ var init_chat2 = __esm({
31321
31398
  transition: "opacity 0.5s ease",
31322
31399
  color: theme.palette.text.primary
31323
31400
  }),
31324
- children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_material53.Typography, { sx: { fontWeight: 600, fontSize: { xs: "1.6rem", md: "2.1rem" }, lineHeight: 1.2 }, children: branding?.brandingText?.trim() || "Bandit AI" })
31401
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.Typography, { sx: { fontWeight: 600, fontSize: { xs: "1.6rem", md: "2.1rem" }, lineHeight: 1.2 }, children: branding?.brandingText?.trim() || "Bandit AI" })
31325
31402
  }
31326
31403
  );
31327
31404
  }
31328
- return branding?.logoBase64 ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(custom_logo_default, { visible: logoVisible, atTop: true }) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(bandit_chat_logo_default, { visible: logoVisible, atTop: true });
31405
+ return branding?.logoBase64 ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(custom_logo_default, { visible: logoVisible, atTop: true }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(bandit_chat_logo_default, { visible: logoVisible, atTop: true });
31329
31406
  })(),
31330
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31331
- import_material53.Box,
31407
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
31408
+ import_material54.Box,
31332
31409
  {
31333
31410
  sx: {
31334
31411
  margin: "0 auto",
@@ -31337,7 +31414,7 @@ var init_chat2 = __esm({
31337
31414
  flexShrink: 0,
31338
31415
  px: isMobile ? 0 : 0
31339
31416
  },
31340
- children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31417
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
31341
31418
  chat_messages_default,
31342
31419
  {
31343
31420
  isStreaming,
@@ -31361,7 +31438,7 @@ var init_chat2 = __esm({
31361
31438
  )
31362
31439
  }
31363
31440
  ),
31364
- showScrollToBottom && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31441
+ showScrollToBottom && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
31365
31442
  chat_scroll_to_bottom_button_default,
31366
31443
  {
31367
31444
  inputHeight,
@@ -31370,8 +31447,8 @@ var init_chat2 = __esm({
31370
31447
  onClick: handleScrollToBottomClick
31371
31448
  }
31372
31449
  ),
31373
- history.length === 0 && componentStatus !== "Loading" && !isMobile && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31374
- import_material53.Box,
31450
+ history.length === 0 && componentStatus !== "Loading" && !isMobile && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
31451
+ import_material54.Box,
31375
31452
  {
31376
31453
  sx: (theme) => ({
31377
31454
  position: "absolute",
@@ -31389,8 +31466,8 @@ var init_chat2 = __esm({
31389
31466
  })
31390
31467
  }
31391
31468
  ),
31392
- /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
31393
- import_material53.Box,
31469
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
31470
+ import_material54.Box,
31394
31471
  {
31395
31472
  sx: {
31396
31473
  display: "flex",
@@ -31401,11 +31478,11 @@ var init_chat2 = __esm({
31401
31478
  maxWidth: "768px"
31402
31479
  },
31403
31480
  children: [
31404
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_material53.Box, { sx: { flex: "1 1 auto" } }),
31405
- history.length === 0 && componentStatus !== "Loading" && !pendingMessage && preferences.chatSuggestionsEnabled && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_material53.Box, { sx: { marginBottom: "20px" }, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(QuerySuggestionPicker, { onSend: handleSend, inputHeight }) }),
31406
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(rate_limit_prompt_default, {}),
31407
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ask_user_card_default, {}),
31408
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31481
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.Box, { sx: { flex: "1 1 auto" } }),
31482
+ history.length === 0 && componentStatus !== "Loading" && !pendingMessage && preferences.chatSuggestionsEnabled && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.Box, { sx: { marginBottom: "20px" }, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(QuerySuggestionPicker, { onSend: handleSend, inputHeight }) }),
31483
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(rate_limit_prompt_default, {}),
31484
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ask_user_card_default, {}),
31485
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
31409
31486
  chat_input_default,
31410
31487
  {
31411
31488
  inputValue,
@@ -31432,24 +31509,12 @@ var init_chat2 = __esm({
31432
31509
  ]
31433
31510
  }
31434
31511
  ),
31435
- preferences.feedbackEnabled && !isMobile && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31436
- FeedbackButton,
31437
- {
31438
- fullScreen: false,
31439
- zIndex: 1300,
31440
- feedbackEmail: packageSettings?.feedbackEmail,
31441
- absolute: true,
31442
- position: {
31443
- bottom: 20,
31444
- right: 20
31445
- }
31446
- }
31447
- ),
31448
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ConnectionStatus, { position: "top", showWhenGood: false })
31512
+ preferences.feedbackEnabled && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(FeedbackPulse_default, { isMobile, feedbackEmail: packageSettings?.feedbackEmail }),
31513
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ConnectionStatus, { position: "top", showWhenGood: false })
31449
31514
  ]
31450
31515
  }
31451
31516
  ),
31452
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(canvas_panel_default, { isMobile })
31517
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(canvas_panel_default, { isMobile })
31453
31518
  ] });
31454
31519
  };
31455
31520
  Chat = () => {
@@ -31475,9 +31540,9 @@ var init_chat2 = __esm({
31475
31540
  });
31476
31541
  if (!allowUnauthenticated && !bypassAuth && !authenticationService.isAuthenticated()) {
31477
31542
  debugLogger.debug("User is not authenticated, redirecting to login");
31478
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_react_router_dom5.Navigate, { to: "/login", replace: true });
31543
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_react_router_dom5.Navigate, { to: "/login", replace: true });
31479
31544
  }
31480
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ChatContent, {});
31545
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ChatContent, {});
31481
31546
  };
31482
31547
  chat_default = Chat;
31483
31548
  }
@@ -31489,12 +31554,12 @@ __export(management_exports, {
31489
31554
  default: () => management_default
31490
31555
  });
31491
31556
  module.exports = __toCommonJS(management_exports);
31492
- var import_react63 = require("react");
31557
+ var import_react64 = require("react");
31493
31558
  var import_useMediaQuery2 = __toESM(require("@mui/material/useMediaQuery"));
31494
- var import_styles34 = require("@mui/material/styles");
31559
+ var import_styles35 = require("@mui/material/styles");
31495
31560
  init_useKnowledgeStore();
31496
31561
  init_indexedDBService();
31497
- var import_material54 = require("@mui/material");
31562
+ var import_material55 = require("@mui/material");
31498
31563
  var import_react_router_dom6 = require("react-router-dom");
31499
31564
 
31500
31565
  // src/modals/chat-modal/chat-modal.tsx
@@ -33415,8 +33480,140 @@ var GenericLoader = ({
33415
33480
  };
33416
33481
  var generic_loader_default = GenericLoader;
33417
33482
 
33418
- // src/modals/chat-modal/chat-modal.tsx
33419
- init_FeedbackButton();
33483
+ // src/components/feedback/FeedbackButton.tsx
33484
+ var import_react18 = require("react");
33485
+ var import_material14 = require("@mui/material");
33486
+ var import_lucide_react4 = require("lucide-react");
33487
+
33488
+ // src/components/feedback/index.tsx
33489
+ init_FeedbackModal();
33490
+
33491
+ // src/components/feedback/FeedbackButton.tsx
33492
+ var import_jsx_runtime14 = require("react/jsx-runtime");
33493
+ var FeedbackButton = ({
33494
+ fullScreen = false,
33495
+ className,
33496
+ zIndex = 1400,
33497
+ feedbackEmail,
33498
+ inline = false,
33499
+ buttonText = "Send Feedback",
33500
+ size = "small",
33501
+ position,
33502
+ absolute = false
33503
+ }) => {
33504
+ const theme = (0, import_material14.useTheme)();
33505
+ const [open, setOpen] = (0, import_react18.useState)(false);
33506
+ const handleOpen = () => setOpen(true);
33507
+ const handleClose = () => setOpen(false);
33508
+ if (inline) {
33509
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
33510
+ buttonText ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
33511
+ import_material14.Button,
33512
+ {
33513
+ variant: "outlined",
33514
+ startIcon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.MessageCircle, {}),
33515
+ onClick: handleOpen,
33516
+ className,
33517
+ size,
33518
+ sx: {
33519
+ borderRadius: 2,
33520
+ textTransform: "none",
33521
+ "&:hover": {
33522
+ transform: "translateY(-1px)",
33523
+ boxShadow: theme.shadows[4]
33524
+ }
33525
+ },
33526
+ children: buttonText
33527
+ }
33528
+ ) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material14.Tooltip, { title: "Send Feedback", arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
33529
+ import_material14.IconButton,
33530
+ {
33531
+ onClick: handleOpen,
33532
+ className,
33533
+ size,
33534
+ sx: {
33535
+ color: theme.palette.primary.main,
33536
+ borderRadius: 2,
33537
+ transition: "all 0.2s ease",
33538
+ "&:hover": {
33539
+ bgcolor: theme.palette.primary.main + "15",
33540
+ transform: "translateY(-1px)"
33541
+ }
33542
+ },
33543
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.MessageCircle, {})
33544
+ }
33545
+ ) }),
33546
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
33547
+ FeedbackModal,
33548
+ {
33549
+ open,
33550
+ onClose: handleClose,
33551
+ feedbackEmail
33552
+ }
33553
+ )
33554
+ ] });
33555
+ }
33556
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
33557
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material14.Zoom, { in: true, timeout: 300, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
33558
+ import_material14.Tooltip,
33559
+ {
33560
+ title: "Send Feedback",
33561
+ placement: "left",
33562
+ arrow: true,
33563
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
33564
+ import_material14.Fab,
33565
+ {
33566
+ size,
33567
+ onClick: handleOpen,
33568
+ className,
33569
+ sx: {
33570
+ position: absolute ? "absolute" : "relative",
33571
+ ...absolute && {
33572
+ bottom: position?.bottom ?? (fullScreen ? 16 : 20),
33573
+ right: position?.right ?? 16,
33574
+ top: position?.top,
33575
+ left: position?.left
33576
+ },
33577
+ zIndex,
33578
+ bgcolor: theme.palette.primary.main,
33579
+ color: theme.palette.primary.contrastText,
33580
+ boxShadow: theme.palette.mode === "dark" ? "0 8px 32px rgba(0,0,0,0.4)" : "0 8px 32px rgba(0,0,0,0.15)",
33581
+ border: `1px solid ${theme.palette.divider}`,
33582
+ transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
33583
+ "&:hover": {
33584
+ bgcolor: theme.palette.primary.dark,
33585
+ transform: "scale(1.05) translateY(-2px)",
33586
+ boxShadow: theme.palette.mode === "dark" ? "0 12px 40px rgba(0,0,0,0.5)" : "0 12px 40px rgba(0,0,0,0.2)"
33587
+ },
33588
+ "&:active": {
33589
+ transform: "scale(0.98) translateY(0px)"
33590
+ },
33591
+ // Subtle pulsing animation
33592
+ animation: "feedbackPulse 3s ease-in-out infinite",
33593
+ "@keyframes feedbackPulse": {
33594
+ "0%, 100%": {
33595
+ boxShadow: theme.palette.mode === "dark" ? "0 8px 32px rgba(0,0,0,0.4)" : "0 8px 32px rgba(0,0,0,0.15)"
33596
+ },
33597
+ "50%": {
33598
+ boxShadow: theme.palette.mode === "dark" ? `0 8px 32px ${theme.palette.primary.main}40` : `0 8px 32px ${theme.palette.primary.main}30`
33599
+ }
33600
+ }
33601
+ },
33602
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.MessageCircle, {})
33603
+ }
33604
+ )
33605
+ }
33606
+ ) }),
33607
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
33608
+ FeedbackModal,
33609
+ {
33610
+ open,
33611
+ onClose: handleClose,
33612
+ feedbackEmail
33613
+ }
33614
+ )
33615
+ ] });
33616
+ };
33420
33617
 
33421
33618
  // src/hooks/useAiChat.ts
33422
33619
  var import_react19 = require("react");
@@ -36206,7 +36403,12 @@ var PreferencesTab = ({
36206
36403
  const timeoutRef = (0, import_react27.useRef)(null);
36207
36404
  const fileInputRef = (0, import_react27.useRef)(null);
36208
36405
  const { exportPreferences, importPreferences, resetToDefaults } = usePreferencesStore();
36209
- const { isServiceAvailable: isTTSSTTAvailable } = useVoiceStore();
36406
+ const {
36407
+ isServiceAvailable: isTTSSTTAvailable,
36408
+ availableVoices,
36409
+ selectedVoice,
36410
+ setSelectedVoice
36411
+ } = useVoiceStore();
36210
36412
  const { hasAdvancedSearch, hasAdvancedMemories } = useFeatures();
36211
36413
  const {
36212
36414
  initialized: syncInitialized,
@@ -36826,6 +37028,19 @@ var PreferencesTab = ({
36826
37028
  ] })
36827
37029
  }
36828
37030
  ),
37031
+ preferences.ttsEnabled && isTTSSTTAvailable && availableVoices.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_material20.FormControl, { size: "small", sx: { ml: 6, mt: 1, maxWidth: 280 }, children: [
37032
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_material20.InputLabel, { id: "tts-voice-label", children: "Voice" }),
37033
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
37034
+ import_material20.Select,
37035
+ {
37036
+ labelId: "tts-voice-label",
37037
+ label: "Voice",
37038
+ value: availableVoices.includes(selectedVoice) ? selectedVoice : "",
37039
+ onChange: (e) => setSelectedVoice(e.target.value),
37040
+ children: availableVoices.map((voice) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_material20.MenuItem, { value: voice, children: voice.split("-")[1] ? voice.split("-")[1].charAt(0).toUpperCase() + voice.split("-")[1].slice(1) : voice }, voice))
37041
+ }
37042
+ )
37043
+ ] }),
36829
37044
  /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
36830
37045
  import_material20.FormControlLabel,
36831
37046
  {
@@ -43993,7 +44208,7 @@ init_authenticationStore();
43993
44208
  init_useNotificationService();
43994
44209
  init_useFeatures();
43995
44210
  init_lucide_icons();
43996
- var import_jsx_runtime53 = require("react/jsx-runtime");
44211
+ var import_jsx_runtime54 = require("react/jsx-runtime");
43997
44212
  var preloadChatPage = () => Promise.resolve().then(() => (init_chat2(), chat_exports));
43998
44213
  var buildCapabilitiesUrl = (gatewayApiUrl) => {
43999
44214
  const trimmed = gatewayApiUrl.replace(/\/$/, "");
@@ -44006,7 +44221,7 @@ var Management = () => {
44006
44221
  const navigate = (0, import_react_router_dom6.useNavigate)();
44007
44222
  const notificationService2 = useNotificationService();
44008
44223
  const isMobile = (0, import_useMediaQuery2.default)("(max-width:900px)");
44009
- const [sidebarOpen, setSidebarOpen] = (0, import_react63.useState)(false);
44224
+ const [sidebarOpen, setSidebarOpen] = (0, import_react64.useState)(false);
44010
44225
  const getOptimalFabLogo = async () => {
44011
44226
  const banditHead6 = "https://cdn.burtson.ai/images/bandit-head.png";
44012
44227
  try {
@@ -44046,17 +44261,17 @@ var Management = () => {
44046
44261
  hasTransparentLogo,
44047
44262
  setHasTransparentLogo
44048
44263
  } = useModelStore();
44049
- const [modalOpen, setModalOpen] = (0, import_react63.useState)(false);
44264
+ const [modalOpen, setModalOpen] = (0, import_react64.useState)(false);
44050
44265
  const banditHead5 = "https://cdn.burtson.ai/images/bandit-head.png";
44051
- const [fabLogo, setFabLogo] = (0, import_react63.useState)(banditHead5);
44052
- const [tabIndex, setTabIndex] = (0, import_react63.useState)(4);
44053
- const [logoFile, setLogoFile] = (0, import_react63.useState)(null);
44054
- const [logoBase64, setLogoBase64] = (0, import_react63.useState)(null);
44055
- const [brandingText, setBrandingText] = (0, import_react63.useState)("");
44056
- const [headerMode, setHeaderMode] = (0, import_react63.useState)("logo");
44057
- const [theme, setTheme] = (0, import_react63.useState)("bandit-dark");
44058
- const [customAvatarBase64, setCustomAvatarBase64] = (0, import_react63.useState)(null);
44059
- const [presetAvatar, setPresetAvatar] = (0, import_react63.useState)(null);
44266
+ const [fabLogo, setFabLogo] = (0, import_react64.useState)(banditHead5);
44267
+ const [tabIndex, setTabIndex] = (0, import_react64.useState)(4);
44268
+ const [logoFile, setLogoFile] = (0, import_react64.useState)(null);
44269
+ const [logoBase64, setLogoBase64] = (0, import_react64.useState)(null);
44270
+ const [brandingText, setBrandingText] = (0, import_react64.useState)("");
44271
+ const [headerMode, setHeaderMode] = (0, import_react64.useState)("logo");
44272
+ const [theme, setTheme] = (0, import_react64.useState)("bandit-dark");
44273
+ const [customAvatarBase64, setCustomAvatarBase64] = (0, import_react64.useState)(null);
44274
+ const [presetAvatar, setPresetAvatar] = (0, import_react64.useState)(null);
44060
44275
  const showSnackbarMessage = (message, severity = "success") => {
44061
44276
  if (severity === "success") {
44062
44277
  notificationService2?.showSuccess(message);
@@ -44064,9 +44279,9 @@ var Management = () => {
44064
44279
  notificationService2?.showError(message);
44065
44280
  }
44066
44281
  };
44067
- const [restoreDialogOpen, setRestoreDialogOpen] = (0, import_react63.useState)(false);
44068
- const [brandingLoaded, setBrandingLoaded] = (0, import_react63.useState)(false);
44069
- const [isLoadingBranding, setIsLoadingBranding] = (0, import_react63.useState)(false);
44282
+ const [restoreDialogOpen, setRestoreDialogOpen] = (0, import_react64.useState)(false);
44283
+ const [brandingLoaded, setBrandingLoaded] = (0, import_react64.useState)(false);
44284
+ const [isLoadingBranding, setIsLoadingBranding] = (0, import_react64.useState)(false);
44070
44285
  const { initModels } = useModelStore();
44071
44286
  const { settings: packageSettings } = usePackageSettingsStore();
44072
44287
  const authToken = useAuthenticationStore((state) => state.token);
@@ -44074,8 +44289,8 @@ var Management = () => {
44074
44289
  const { hasAdminDashboard, hasLimitedAdminDashboard, getCurrentTier, hasAdvancedSearch } = useFeatures();
44075
44290
  const { showAdminPanel, showLimitedAdminPanel } = useFeatureVisibility();
44076
44291
  const { provider: currentProvider, config: currentProviderConfig } = useAIProviderStore();
44077
- const [seedPacksEnabled, setSeedPacksEnabled] = (0, import_react63.useState)(false);
44078
- const [localSelectedModel, setLocalSelectedModel] = (0, import_react63.useState)({
44292
+ const [seedPacksEnabled, setSeedPacksEnabled] = (0, import_react64.useState)(false);
44293
+ const [localSelectedModel, setLocalSelectedModel] = (0, import_react64.useState)({
44079
44294
  name: "",
44080
44295
  tagline: "",
44081
44296
  systemPrompt: "",
@@ -44088,7 +44303,7 @@ var Management = () => {
44088
44303
  loadDocuments,
44089
44304
  clearAllDocuments
44090
44305
  } = useKnowledgeStore2();
44091
- (0, import_react63.useEffect)(() => {
44306
+ (0, import_react64.useEffect)(() => {
44092
44307
  if (selectedModel) {
44093
44308
  const selected = availableModels.find((m) => m.name === selectedModel);
44094
44309
  if (selected) {
@@ -44112,7 +44327,7 @@ var Management = () => {
44112
44327
  }
44113
44328
  }
44114
44329
  }, [selectedModel, availableModels]);
44115
- const loadBrandingConfig = (0, import_react63.useCallback)(async () => {
44330
+ const loadBrandingConfig = (0, import_react64.useCallback)(async () => {
44116
44331
  if (isLoadingBranding || brandingLoaded) {
44117
44332
  debugLogger.warn("Branding loading already in progress or completed, skipping");
44118
44333
  return;
@@ -44229,15 +44444,15 @@ var Management = () => {
44229
44444
  setTagline,
44230
44445
  setTheme
44231
44446
  ]);
44232
- (0, import_react63.useEffect)(() => {
44447
+ (0, import_react64.useEffect)(() => {
44233
44448
  void loadBrandingConfig();
44234
44449
  }, [loadBrandingConfig]);
44235
44450
  const handleOpenModal = () => setModalOpen(true);
44236
44451
  const handleCloseModal = () => setModalOpen(false);
44237
- (0, import_react63.useEffect)(() => {
44452
+ (0, import_react64.useEffect)(() => {
44238
44453
  getOptimalFabLogo().then(setFabLogo);
44239
44454
  }, []);
44240
- (0, import_react63.useEffect)(() => {
44455
+ (0, import_react64.useEffect)(() => {
44241
44456
  if (logoBase64) {
44242
44457
  setFabLogo(logoBase64);
44243
44458
  } else {
@@ -44690,7 +44905,7 @@ var Management = () => {
44690
44905
  reader.readAsText(file);
44691
44906
  }
44692
44907
  };
44693
- (0, import_react63.useEffect)(() => {
44908
+ (0, import_react64.useEffect)(() => {
44694
44909
  if (localSelectedModel.selectedModel && !availableModels.some((m) => m.name === localSelectedModel.selectedModel)) {
44695
44910
  setLocalSelectedModel((prev) => ({
44696
44911
  ...prev,
@@ -44698,10 +44913,10 @@ var Management = () => {
44698
44913
  }));
44699
44914
  }
44700
44915
  }, [availableModels, localSelectedModel.selectedModel]);
44701
- (0, import_react63.useEffect)(() => {
44916
+ (0, import_react64.useEffect)(() => {
44702
44917
  loadDocuments();
44703
44918
  }, [loadDocuments]);
44704
- (0, import_react63.useEffect)(() => {
44919
+ (0, import_react64.useEffect)(() => {
44705
44920
  const gatewayApiUrl = packageSettings?.gatewayApiUrl;
44706
44921
  if (!gatewayApiUrl || gatewayApiUrl.toLowerCase().startsWith("playground://")) {
44707
44922
  setSeedPacksEnabled(false);
@@ -44744,9 +44959,9 @@ var Management = () => {
44744
44959
  isActive = false;
44745
44960
  };
44746
44961
  }, [packageSettings?.gatewayApiUrl, authToken]);
44747
- const currentTheme = (0, import_react63.useMemo)(() => {
44962
+ const currentTheme = (0, import_react64.useMemo)(() => {
44748
44963
  const baseTheme = predefinedThemes[theme] || banditDarkTheme;
44749
- return (0, import_styles34.createTheme)(baseTheme, {
44964
+ return (0, import_styles35.createTheme)(baseTheme, {
44750
44965
  // Management-scoped density: condenses every settings tab at once. This
44751
44966
  // theme only wraps the admin console, so the chat UI is unaffected.
44752
44967
  typography: {
@@ -44801,43 +45016,43 @@ var Management = () => {
44801
45016
  const allNavTabs = [
44802
45017
  {
44803
45018
  label: "Personalities",
44804
- icon: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(FaceRetouchingNaturalIcon, {}),
45019
+ icon: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(FaceRetouchingNaturalIcon, {}),
44805
45020
  requiresFeature: "limitedAdminDashboard",
44806
45021
  requiresAdmin: true
44807
45022
  },
44808
45023
  {
44809
45024
  label: "Branding",
44810
- icon: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(BrushIcon, {}),
45025
+ icon: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(BrushIcon, {}),
44811
45026
  requiresFeature: "limitedAdminDashboard",
44812
45027
  requiresAdmin: true
44813
45028
  },
44814
45029
  {
44815
45030
  label: "Knowledge",
44816
- icon: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(MenuBookIcon, {}),
45031
+ icon: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(MenuBookIcon, {}),
44817
45032
  requiresFeature: "limitedAdminDashboard",
44818
45033
  requiresAdmin: true
44819
45034
  },
44820
45035
  {
44821
45036
  label: "Storage",
44822
- icon: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(StorageIcon, {}),
45037
+ icon: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(StorageIcon, {}),
44823
45038
  requiresFeature: "limitedAdminDashboard",
44824
45039
  requiresAdmin: true
44825
45040
  },
44826
45041
  {
44827
45042
  label: "Preferences",
44828
- icon: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(TuneIcon, {}),
45043
+ icon: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(TuneIcon, {}),
44829
45044
  requiresFeature: "limitedAdminDashboard",
44830
45045
  requiresAdmin: false
44831
45046
  },
44832
45047
  {
44833
45048
  label: "Provider",
44834
- icon: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(CloudIcon, {}),
45049
+ icon: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(CloudIcon, {}),
44835
45050
  requiresFeature: "advancedSearch",
44836
45051
  requiresAdmin: true
44837
45052
  },
44838
45053
  {
44839
45054
  label: "Tools",
44840
- icon: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(BuildIcon, {}),
45055
+ icon: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(BuildIcon, {}),
44841
45056
  requiresFeature: "advancedSearch",
44842
45057
  requiresAdmin: true
44843
45058
  }
@@ -44865,7 +45080,7 @@ var Management = () => {
44865
45080
  });
44866
45081
  const preferredDefaultTabIndex = navTabs.findIndex((tab) => tab.label === "Preferences");
44867
45082
  const defaultTabIndex = preferredDefaultTabIndex >= 0 ? preferredDefaultTabIndex : 0;
44868
- (0, import_react63.useEffect)(() => {
45083
+ (0, import_react64.useEffect)(() => {
44869
45084
  setTabIndex((current) => {
44870
45085
  if (current < 0 || current >= navTabs.length) {
44871
45086
  return defaultTabIndex;
@@ -44875,8 +45090,8 @@ var Management = () => {
44875
45090
  }, [navTabs.length, defaultTabIndex]);
44876
45091
  const mobileQuickTabs = navTabs.slice(0, 5);
44877
45092
  const hasMobileOverflowTabs = navTabs.length > mobileQuickTabs.length;
44878
- const navigationContent = /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
44879
- import_material54.Box,
45093
+ const navigationContent = /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
45094
+ import_material55.Box,
44880
45095
  {
44881
45096
  sx: {
44882
45097
  display: "flex",
@@ -44886,29 +45101,29 @@ var Management = () => {
44886
45101
  bgcolor: "inherit"
44887
45102
  },
44888
45103
  children: [
44889
- isMobile && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
44890
- import_material54.Box,
45104
+ isMobile && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45105
+ import_material55.Box,
44891
45106
  {
44892
45107
  sx: {
44893
45108
  height: 6,
44894
45109
  width: 56,
44895
45110
  borderRadius: 999,
44896
- bgcolor: (theme2) => (0, import_styles34.alpha)(theme2.palette.text.primary, 0.18),
45111
+ bgcolor: (theme2) => (0, import_styles35.alpha)(theme2.palette.text.primary, 0.18),
44897
45112
  alignSelf: "center",
44898
45113
  mt: 1.25,
44899
45114
  mb: 0.75
44900
45115
  }
44901
45116
  }
44902
45117
  ),
44903
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.Box, { sx: { p: isMobile ? 2.5 : 3, pb: isMobile ? 1.5 : 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
44904
- import_material54.Button,
45118
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_material55.Box, { sx: { p: isMobile ? 2.5 : 3, pb: isMobile ? 1.5 : 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45119
+ import_material55.Button,
44905
45120
  {
44906
45121
  onClick: () => {
44907
45122
  if (isMobile) setSidebarOpen(false);
44908
45123
  navigate("/chat");
44909
45124
  },
44910
45125
  onMouseEnter: preloadChatPage,
44911
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ChevronLeftIcon, { sx: { fontSize: 20 } }),
45126
+ startIcon: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(ChevronLeftIcon, { sx: { fontSize: 20 } }),
44912
45127
  fullWidth: true,
44913
45128
  variant: "outlined",
44914
45129
  sx: {
@@ -44935,9 +45150,9 @@ var Management = () => {
44935
45150
  children: "Back to Chat"
44936
45151
  }
44937
45152
  ) }),
44938
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.Divider, { sx: { mx: isMobile ? 2 : 3, mb: 2, opacity: 0.6 } }),
44939
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.Box, { sx: { flex: 1, px: isMobile ? 1.5 : 2, pb: 3, overflowY: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.List, { sx: { px: 0, py: 0 }, children: navTabs.map((tab, idx) => /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
44940
- import_material54.ListItemButton,
45153
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_material55.Divider, { sx: { mx: isMobile ? 2 : 3, mb: 2, opacity: 0.6 } }),
45154
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_material55.Box, { sx: { flex: 1, px: isMobile ? 1.5 : 2, pb: 3, overflowY: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_material55.List, { sx: { px: 0, py: 0 }, children: navTabs.map((tab, idx) => /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
45155
+ import_material55.ListItemButton,
44941
45156
  {
44942
45157
  selected: tabIndex === idx,
44943
45158
  onClick: () => {
@@ -44977,9 +45192,9 @@ var Management = () => {
44977
45192
  "& .MuiListItemIcon-root svg": { width: 17, height: 17 }
44978
45193
  },
44979
45194
  children: [
44980
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.ListItemIcon, { children: tab.icon }),
44981
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
44982
- import_material54.ListItemText,
45195
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_material55.ListItemIcon, { children: tab.icon }),
45196
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45197
+ import_material55.ListItemText,
44983
45198
  {
44984
45199
  primary: tab.label,
44985
45200
  primaryTypographyProps: {
@@ -44996,10 +45211,10 @@ var Management = () => {
44996
45211
  }
44997
45212
  );
44998
45213
  if (!brandingLoaded) return null;
44999
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_material54.ThemeProvider, { theme: currentTheme, children: [
45000
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.CssBaseline, {}),
45001
- /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
45002
- import_material54.Box,
45214
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_material55.ThemeProvider, { theme: currentTheme, children: [
45215
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_material55.CssBaseline, {}),
45216
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
45217
+ import_material55.Box,
45003
45218
  {
45004
45219
  display: "flex",
45005
45220
  height: "100vh",
@@ -45011,8 +45226,8 @@ var Management = () => {
45011
45226
  position: "relative"
45012
45227
  },
45013
45228
  children: [
45014
- isMobile && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
45015
- import_material54.Box,
45229
+ isMobile && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
45230
+ import_material55.Box,
45016
45231
  {
45017
45232
  sx: {
45018
45233
  width: "100%",
@@ -45031,8 +45246,8 @@ var Management = () => {
45031
45246
  boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
45032
45247
  },
45033
45248
  children: [
45034
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45035
- import_material54.Button,
45249
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45250
+ import_material55.Button,
45036
45251
  {
45037
45252
  onClick: () => navigate("/chat"),
45038
45253
  onMouseEnter: preloadChatPage,
@@ -45045,11 +45260,11 @@ var Management = () => {
45045
45260
  color: "primary.main",
45046
45261
  bgcolor: (theme2) => theme2.palette.mode === "dark" ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.04)"
45047
45262
  },
45048
- children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ChevronLeftIcon, { sx: { fontSize: 22 } })
45263
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(ChevronLeftIcon, { sx: { fontSize: 22 } })
45049
45264
  }
45050
45265
  ),
45051
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45052
- import_material54.Button,
45266
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45267
+ import_material55.Button,
45053
45268
  {
45054
45269
  onClick: () => setSidebarOpen((o) => !o),
45055
45270
  sx: {
@@ -45070,7 +45285,7 @@ var Management = () => {
45070
45285
  transform: sidebarOpen ? "rotate(90deg) scale(0.95)" : "scale(0.95)"
45071
45286
  }
45072
45287
  },
45073
- children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45288
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45074
45289
  "path",
45075
45290
  {
45076
45291
  d: sidebarOpen ? "M18 6L6 18M6 6L18 18" : "M3 12H21M3 6H21M3 18H21",
@@ -45082,8 +45297,8 @@ var Management = () => {
45082
45297
  ) })
45083
45298
  }
45084
45299
  ),
45085
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45086
- import_material54.Typography,
45300
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45301
+ import_material55.Typography,
45087
45302
  {
45088
45303
  variant: "h6",
45089
45304
  sx: {
@@ -45095,14 +45310,14 @@ var Management = () => {
45095
45310
  children: "Management"
45096
45311
  }
45097
45312
  ),
45098
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_material54.Box, { sx: {
45313
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_material55.Box, { sx: {
45099
45314
  px: 2,
45100
45315
  py: 0.5,
45101
45316
  borderRadius: 2,
45102
45317
  bgcolor: (theme2) => theme2.palette.mode === "dark" ? "rgba(25,118,210,0.12)" : "rgba(25,118,210,0.08)",
45103
45318
  border: (theme2) => `1px solid ${theme2.palette.primary.main}20`
45104
- }, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45105
- import_material54.Typography,
45319
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45320
+ import_material55.Typography,
45106
45321
  {
45107
45322
  variant: "caption",
45108
45323
  sx: {
@@ -45116,8 +45331,8 @@ var Management = () => {
45116
45331
  ]
45117
45332
  }
45118
45333
  ),
45119
- isMobile && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
45120
- import_material54.Box,
45334
+ isMobile && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
45335
+ import_material55.Box,
45121
45336
  {
45122
45337
  sx: {
45123
45338
  width: "100%",
@@ -45134,8 +45349,8 @@ var Management = () => {
45134
45349
  mobileQuickTabs.map((tab) => {
45135
45350
  const quickTabIndex = navTabs.findIndex((navTab) => navTab.label === tab.label);
45136
45351
  const selected = tabIndex === quickTabIndex;
45137
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45138
- import_material54.Button,
45352
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45353
+ import_material55.Button,
45139
45354
  {
45140
45355
  size: "small",
45141
45356
  onClick: () => setTabIndex(quickTabIndex),
@@ -45150,7 +45365,7 @@ var Management = () => {
45150
45365
  fontWeight: selected ? 700 : 600,
45151
45366
  bgcolor: selected ? (theme2) => theme2.palette.mode === "dark" ? "rgba(25,118,210,0.2)" : "rgba(25,118,210,0.12)" : "transparent",
45152
45367
  color: selected ? "primary.main" : "text.secondary",
45153
- border: (theme2) => selected ? `1px solid ${theme2.palette.primary.main}66` : `1px solid ${(0, import_styles34.alpha)(theme2.palette.divider, 0.45)}`,
45368
+ border: (theme2) => selected ? `1px solid ${theme2.palette.primary.main}66` : `1px solid ${(0, import_styles35.alpha)(theme2.palette.divider, 0.45)}`,
45154
45369
  "&:hover": {
45155
45370
  bgcolor: (theme2) => theme2.palette.mode === "dark" ? "rgba(25,118,210,0.16)" : "rgba(25,118,210,0.1)"
45156
45371
  }
@@ -45160,8 +45375,8 @@ var Management = () => {
45160
45375
  tab.label
45161
45376
  );
45162
45377
  }),
45163
- hasMobileOverflowTabs && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45164
- import_material54.Button,
45378
+ hasMobileOverflowTabs && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45379
+ import_material55.Button,
45165
45380
  {
45166
45381
  size: "small",
45167
45382
  onClick: () => setSidebarOpen(true),
@@ -45175,7 +45390,7 @@ var Management = () => {
45175
45390
  fontSize: "0.78rem",
45176
45391
  fontWeight: 600,
45177
45392
  color: "text.secondary",
45178
- border: (theme2) => `1px dashed ${(0, import_styles34.alpha)(theme2.palette.divider, 0.6)}`
45393
+ border: (theme2) => `1px dashed ${(0, import_styles35.alpha)(theme2.palette.divider, 0.6)}`
45179
45394
  },
45180
45395
  children: "More"
45181
45396
  }
@@ -45183,8 +45398,8 @@ var Management = () => {
45183
45398
  ]
45184
45399
  }
45185
45400
  ),
45186
- isMobile ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45187
- import_material54.SwipeableDrawer,
45401
+ isMobile ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45402
+ import_material55.SwipeableDrawer,
45188
45403
  {
45189
45404
  anchor: "bottom",
45190
45405
  open: sidebarOpen,
@@ -45204,8 +45419,8 @@ var Management = () => {
45204
45419
  },
45205
45420
  children: navigationContent
45206
45421
  }
45207
- ) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45208
- import_material54.Box,
45422
+ ) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45423
+ import_material55.Box,
45209
45424
  {
45210
45425
  sx: {
45211
45426
  width: 240,
@@ -45228,8 +45443,8 @@ var Management = () => {
45228
45443
  children: navigationContent
45229
45444
  }
45230
45445
  ),
45231
- /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
45232
- import_material54.Box,
45446
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
45447
+ import_material55.Box,
45233
45448
  {
45234
45449
  sx: {
45235
45450
  flex: 1,
@@ -45248,7 +45463,7 @@ var Management = () => {
45248
45463
  transition: "margin-left 0.2s"
45249
45464
  },
45250
45465
  children: [
45251
- navTabs[tabIndex]?.label === "Personalities" && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45466
+ navTabs[tabIndex]?.label === "Personalities" && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45252
45467
  PersonalitiesTab_default,
45253
45468
  {
45254
45469
  availableModels,
@@ -45267,7 +45482,7 @@ var Management = () => {
45267
45482
  showSnackbar: showSnackbarMessage
45268
45483
  }
45269
45484
  ),
45270
- navTabs[tabIndex]?.label === "Branding" && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45485
+ navTabs[tabIndex]?.label === "Branding" && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45271
45486
  BrandingTab_default,
45272
45487
  {
45273
45488
  logoFile,
@@ -45288,7 +45503,7 @@ var Management = () => {
45288
45503
  setLogoBase64
45289
45504
  }
45290
45505
  ),
45291
- navTabs[tabIndex]?.label === "Knowledge" && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45506
+ navTabs[tabIndex]?.label === "Knowledge" && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45292
45507
  KnowledgeHubTab_default,
45293
45508
  {
45294
45509
  documents,
@@ -45301,8 +45516,8 @@ var Management = () => {
45301
45516
  seedPacksEnabled
45302
45517
  }
45303
45518
  ),
45304
- navTabs[tabIndex]?.label === "Storage" && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(StorageTab_default, { currentTheme }),
45305
- navTabs[tabIndex]?.label === "Preferences" && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45519
+ navTabs[tabIndex]?.label === "Storage" && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(StorageTab_default, { currentTheme }),
45520
+ navTabs[tabIndex]?.label === "Preferences" && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45306
45521
  PreferencesTab_default,
45307
45522
  {
45308
45523
  preferences,
@@ -45312,13 +45527,13 @@ var Management = () => {
45312
45527
  showSnackbar: showSnackbarMessage
45313
45528
  }
45314
45529
  ),
45315
- navTabs[tabIndex]?.label === "Provider" && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ProviderTab, {}),
45316
- navTabs[tabIndex]?.label === "Tools" && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(MCPToolsTabV2_default, {})
45530
+ navTabs[tabIndex]?.label === "Provider" && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(ProviderTab, {}),
45531
+ navTabs[tabIndex]?.label === "Tools" && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(MCPToolsTabV2_default, {})
45317
45532
  ]
45318
45533
  }
45319
45534
  ),
45320
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45321
- import_material54.Fab,
45535
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45536
+ import_material55.Fab,
45322
45537
  {
45323
45538
  "aria-label": "AI",
45324
45539
  onClick: handleOpenModal,
@@ -45339,7 +45554,7 @@ var Management = () => {
45339
45554
  boxShadow: theme2.shadows[6],
45340
45555
  zIndex: 2e3
45341
45556
  }),
45342
- children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45557
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
45343
45558
  "img",
45344
45559
  {
45345
45560
  src: fabLogo,
@@ -45353,7 +45568,7 @@ var Management = () => {
45353
45568
  )
45354
45569
  }
45355
45570
  ),
45356
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(chat_modal_default, { open: modalOpen, onClose: handleCloseModal })
45571
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(chat_modal_default, { open: modalOpen, onClose: handleCloseModal })
45357
45572
  ]
45358
45573
  }
45359
45574
  )