@burtson-labs/bandit-engine 2.0.136 → 2.0.138

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.
@@ -9776,7 +9776,7 @@ var MCPToolsTabV2_default = MCPToolsTabV2;
9776
9776
 
9777
9777
  // src/management/management.tsx
9778
9778
  import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
9779
- var preloadChatPage = () => import("./chat-AIQIJCAR.mjs");
9779
+ var preloadChatPage = () => import("./chat-VBE333NU.mjs");
9780
9780
  var buildCapabilitiesUrl = (gatewayApiUrl) => {
9781
9781
  const trimmed = gatewayApiUrl.replace(/\/$/, "");
9782
9782
  if (trimmed.endsWith("/api")) {
@@ -11149,4 +11149,4 @@ export {
11149
11149
  useGatewayMemory,
11150
11150
  management_default
11151
11151
  };
11152
- //# sourceMappingURL=chunk-LG4S6XLH.mjs.map
11152
+ //# sourceMappingURL=chunk-WBWVXJF3.mjs.map
package/dist/index.js CHANGED
@@ -19345,6 +19345,8 @@ ${sanitize(
19345
19345
  const hasFeedbackAction = isFeedbackEnabled && isMobile;
19346
19346
  const hasSttAction = isSTTAvailable && !isVoiceModeEnabled;
19347
19347
  const hasVoicePickerAction = isMobile && isTTSAvailable && availableVoices.length > 0;
19348
+ const hasComposeContent = !!inputValue.trim() || pastedImages.length > 0 || fileInputs.length > 0;
19349
+ const showSendButton = streamingActive || hasComposeContent || !isVoiceModeEligible;
19348
19350
  const hasSecondaryActions = isMobile && (hasAttachmentAction || hasMemoryAction || hasFeedbackAction || hasSttAction || hasVoicePickerAction);
19349
19351
  (0, import_react23.useEffect)(() => {
19350
19352
  if (!isMobile || !hasSecondaryActions) {
@@ -19409,6 +19411,33 @@ ${sanitize(
19409
19411
  if (!hasSttAction) return null;
19410
19412
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material18.Box, { sx: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(transcriber_default, { onTranscriptionCompleted: handleTranscriptionCompleted }) }, key ?? "stt");
19411
19413
  };
19414
+ const renderVoiceModeButton = (key) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19415
+ import_material18.Tooltip,
19416
+ {
19417
+ title: !isVoiceModeEnabled ? "Enable voice mode" : voiceStatus === "error" ? voiceError || "Voice mode error" : voiceStatus === "processing" ? "Transcribing your speech" : voiceStatus === "recording" ? "Recording - click to stop" : voiceStatus === "initializing" ? "Preparing microphone" : "Listening - click to turn off",
19418
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19419
+ import_material18.IconButton,
19420
+ {
19421
+ onClick: toggleVoiceMode,
19422
+ sx: {
19423
+ width: sendIconSize,
19424
+ height: sendIconSize,
19425
+ borderRadius: "50%",
19426
+ bgcolor: isVoiceModeEnabled ? (0, import_styles10.alpha)(theme.palette.error.main, theme.palette.mode === "dark" ? 0.45 : 0.3) : fileText,
19427
+ color: isVoiceModeEnabled ? theme.palette.common.white : fileIconBg,
19428
+ boxShadow: isVoiceModeEnabled && voiceStatus === "recording" ? `0 0 0 2px ${(0, import_styles10.alpha)(theme.palette.error.main, 0.25)}` : "none",
19429
+ transform: isVoiceModeEnabled && voiceStatus === "recording" ? "scale(1.05)" : "none",
19430
+ transition: "transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease",
19431
+ "&:hover": {
19432
+ bgcolor: isVoiceModeEnabled ? (0, import_styles10.alpha)(theme.palette.error.main, theme.palette.mode === "dark" ? 0.55 : 0.38) : hoverBadgeBackground
19433
+ }
19434
+ },
19435
+ children: !isVoiceModeEnabled ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GraphicEqIcon, { fontSize: "small" }) : voiceStatus === "processing" || voiceStatus === "initializing" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material18.CircularProgress, { size: 18, sx: { color: theme.palette.common.white } }) : voiceStatus === "error" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(HearingDisabledIcon, { fontSize: "small", sx: { color: theme.palette.error.light } }) : voiceStatus === "recording" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GraphicEqIcon, { fontSize: "small", sx: { color: theme.palette.error.light } }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GraphicEqIcon, { fontSize: "small", sx: { color: theme.palette.common.white } })
19436
+ }
19437
+ )
19438
+ },
19439
+ key ?? "voice-mode"
19440
+ );
19412
19441
  const renderVoicePickerButton = (key) => {
19413
19442
  if (!hasVoicePickerAction) return null;
19414
19443
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material18.Tooltip, { title: `Voice: ${selectedVoice ? toTitleCase(selectedVoice.split("-")[1] ?? selectedVoice) : "Default"}`, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
@@ -19656,51 +19685,22 @@ ${sanitize(
19656
19685
  minHeight: primaryIconSize
19657
19686
  },
19658
19687
  children: [
19659
- isVoiceModeEligible && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
19660
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19661
- import_material18.Tooltip,
19662
- {
19663
- title: !isVoiceModeEnabled ? "Enable voice mode" : voiceStatus === "error" ? voiceError || "Voice mode error" : voiceStatus === "processing" ? "Transcribing your speech" : voiceStatus === "recording" ? "Recording - click to stop" : voiceStatus === "initializing" ? "Preparing microphone" : "Listening - click to turn off",
19664
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19665
- import_material18.IconButton,
19666
- {
19667
- onClick: toggleVoiceMode,
19668
- sx: {
19669
- width: primaryIconSize,
19670
- height: primaryIconSize,
19671
- borderRadius: "50%",
19672
- bgcolor: isVoiceModeEnabled ? (0, import_styles10.alpha)(theme.palette.error.main, theme.palette.mode === "dark" ? 0.45 : 0.3) : badgeBackground,
19673
- color: isVoiceModeEnabled ? theme.palette.common.white : fileText,
19674
- boxShadow: isVoiceModeEnabled && voiceStatus === "recording" ? `0 0 0 2px ${(0, import_styles10.alpha)(theme.palette.error.main, 0.25)}` : "none",
19675
- transform: isVoiceModeEnabled && voiceStatus === "recording" ? "scale(1.05)" : "none",
19676
- transition: "transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease",
19677
- "&:hover": {
19678
- bgcolor: isVoiceModeEnabled ? (0, import_styles10.alpha)(theme.palette.error.main, theme.palette.mode === "dark" ? 0.55 : 0.38) : hoverBadgeBackground
19679
- }
19680
- },
19681
- children: !isVoiceModeEnabled ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GraphicEqIcon, { fontSize: "small", sx: { color: theme.palette.mode === "dark" ? fileText : theme.palette.text.secondary } }) : voiceStatus === "processing" || voiceStatus === "initializing" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material18.CircularProgress, { size: 18, sx: { color: fileText } }) : voiceStatus === "error" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(HearingDisabledIcon, { fontSize: "small", sx: { color: theme.palette.error.light } }) : voiceStatus === "recording" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GraphicEqIcon, { fontSize: "small", sx: { color: theme.palette.error.light } }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GraphicEqIcon, { fontSize: "small", sx: { color: theme.palette.common.white } })
19682
- }
19683
- )
19684
- }
19685
- ),
19686
- !isMobile && isVoiceModeEnabled && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19687
- import_material18.Typography,
19688
- {
19689
- variant: "caption",
19690
- sx: {
19691
- color: voiceStatus === "error" ? theme.palette.error.main : voiceStatus === "processing" ? theme.palette.warning.main : fileText,
19692
- maxWidth: 240,
19693
- overflow: "hidden",
19694
- textOverflow: "ellipsis",
19695
- whiteSpace: "nowrap"
19696
- },
19697
- children: voiceStatus === "error" ? voiceError || "Voice mode unavailable" : voiceStatus === "initializing" ? "Starting voice mode..." : voiceStatus === "recording" ? "Recording..." : voiceStatus === "processing" ? "Transcribing..." : voiceLastTranscript ? `Heard: "${voiceLastTranscript.length > 60 ? `${voiceLastTranscript.slice(0, 57)}...` : voiceLastTranscript}"` : "Listening..."
19698
- }
19699
- )
19700
- ] }),
19701
19688
  !isMobile && renderAttachmentButton("attach-inline"),
19702
19689
  !isMobile && renderMemoryButton("memory-inline"),
19703
- !isMobile && renderSttButton("stt-inline"),
19690
+ !isMobile && isVoiceModeEligible && isVoiceModeEnabled && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19691
+ import_material18.Typography,
19692
+ {
19693
+ variant: "caption",
19694
+ sx: {
19695
+ color: voiceStatus === "error" ? theme.palette.error.main : voiceStatus === "processing" ? theme.palette.warning.main : fileText,
19696
+ maxWidth: 240,
19697
+ overflow: "hidden",
19698
+ textOverflow: "ellipsis",
19699
+ whiteSpace: "nowrap"
19700
+ },
19701
+ children: voiceStatus === "error" ? voiceError || "Voice mode unavailable" : voiceStatus === "initializing" ? "Starting voice mode..." : voiceStatus === "recording" ? "Recording..." : voiceStatus === "processing" ? "Transcribing..." : voiceLastTranscript ? `Heard: "${voiceLastTranscript.length > 60 ? `${voiceLastTranscript.slice(0, 57)}...` : voiceLastTranscript}"` : "Listening..."
19702
+ }
19703
+ ),
19704
19704
  isMobile && hasSecondaryActions && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19705
19705
  import_material18.IconButton,
19706
19706
  {
@@ -19756,7 +19756,9 @@ ${sanitize(
19756
19756
  ),
19757
19757
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material18.Box, { sx: { display: "flex", alignItems: "center", gap: isMobile ? 0.6 : 1 }, children: [
19758
19758
  !isMobile && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(engine_picker_default, {}),
19759
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material18.Tooltip, { title: isStreaming ? "Stop response" : "Send message", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19759
+ !isMobile && renderSttButton("stt-right"),
19760
+ isVoiceModeEligible && !showSendButton && renderVoiceModeButton("voice-right"),
19761
+ showSendButton && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material18.Tooltip, { title: isStreaming ? "Stop response" : "Send message", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19760
19762
  import_material18.IconButton,
19761
19763
  {
19762
19764
  onClick: isStreaming ? onStop || (() => {
@@ -26038,8 +26040,10 @@ var init_enhanced_mobile_conversations_modal = __esm({
26038
26040
  // Keep in sync with MOBILE_CONVERSATIONS_DRAWER_WIDTH in chat.tsx
26039
26041
  // (the chat shell translates by the same amount).
26040
26042
  width: "min(calc(100vw - 56px), 360px)",
26041
- // top/bottom stretch instead of 100dvh — iOS standalone
26042
- // under-reports dvh, leaving a dead band above the home bar.
26043
+ // Explicit 100lvh overflows iOS standalone's under-reported
26044
+ // viewport downward — bottom-anchoring alone stops short.
26045
+ height: "100dvh",
26046
+ "@supports (height: 100lvh)": { height: "100lvh" },
26043
26047
  bgcolor: theme.palette.background.paper,
26044
26048
  display: "flex",
26045
26049
  flexDirection: "column",
@@ -31618,18 +31622,20 @@ var init_chat2 = __esm({
31618
31622
  sx: (theme) => ({
31619
31623
  display: "flex",
31620
31624
  flexDirection: "column",
31621
- // Stretch via top/bottom instead of 100dvh — the iOS standalone
31622
- // webview under-reports dvh and left a dead band above the home
31623
- // indicator; inset-stretched fixed elements get the real viewport.
31625
+ // iOS standalone under-reports both dvh AND the fixed-position
31626
+ // containing block, stranding a dead band above the home bar.
31627
+ // An explicit 100lvh height can overflow that short viewport
31628
+ // downward, which bottom-anchoring cannot.
31624
31629
  overflow: "hidden",
31625
31630
  bgcolor: theme.palette.chat.shell,
31626
31631
  color: theme.palette.text.primary,
31627
31632
  position: "fixed",
31628
31633
  top: 0,
31629
31634
  bottom: 0,
31635
+ height: "100dvh",
31636
+ "@supports (height: 100lvh)": { height: "100lvh" },
31630
31637
  left: drawerOpen && !isMobile ? "340px" : 0,
31631
31638
  width: !isMobile && canvasOpen ? `calc(100vw - ${drawerOpen ? "340px" : "0px"} - ${CANVAS_WIDTH})` : drawerOpen && !isMobile ? "calc(100vw - 340px)" : "100vw",
31632
- zIndex: 0,
31633
31639
  // Claude-style push (mobile only; desktop stays flush): the chat
31634
31640
  // shell slides right as a full-height rounded card — exactly like
31635
31641
  // Claude iOS, where the card runs edge-to-edge vertically and the
@@ -31640,15 +31646,20 @@ var init_chat2 = __esm({
31640
31646
  // status area, the bottom stays flush with the screen edge, and the
31641
31647
  // motion reads as the native sheet-behind effect instead of the
31642
31648
  // content lurching downward.
31643
- transform: isMobile && mobileConversationsOpen ? "translateX(min(calc(100vw - 56px), 360px)) scale(0.93)" : "none",
31649
+ // Slides 12px OVER the drawer's edge (not edge-to-edge) and rides
31650
+ // above it in z-order, so the card's shadow falls on the drawer —
31651
+ // the overlapped-sheet look.
31652
+ transform: isMobile && mobileConversationsOpen ? "translateX(calc(min(calc(100vw - 56px), 360px) - 12px)) scale(0.93)" : "none",
31644
31653
  transformOrigin: "left bottom",
31645
31654
  borderRadius: isMobile && mobileConversationsOpen ? "36px" : 0,
31655
+ zIndex: isMobile && mobileConversationsOpen ? theme.zIndex.modal + 1 : 0,
31646
31656
  // Hairline border so the rounded card reads even when the backdrop
31647
31657
  // is the same near-black as the shell.
31648
31658
  border: isMobile && mobileConversationsOpen ? `1px solid ${theme.palette.mode === "dark" ? "rgba(255,255,255,0.14)" : "rgba(0,0,0,0.12)"}` : "none",
31649
31659
  boxShadow: isMobile && mobileConversationsOpen ? `0 12px 40px ${theme.palette.mode === "dark" ? "rgba(0,0,0,0.55)" : "rgba(0,0,0,0.25)"}` : "none",
31650
31660
  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"
31651
31661
  }),
31662
+ onClick: isMobile && mobileConversationsOpen ? () => setMobileConversationsOpen(false) : void 0,
31652
31663
  children: [
31653
31664
  /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
31654
31665
  chat_app_bar_default,
@@ -31753,7 +31764,10 @@ var init_chat2 = __esm({
31753
31764
  px: isMobile ? 1 : 2,
31754
31765
  // Reduce padding on mobile for better width utilization
31755
31766
  pb: logoOnly ? 0 : `${inputHeight + 24}px`,
31756
- maxHeight: isMobile ? "calc(var(--vh, 1vh) * 100)" : "100%",
31767
+ // The flex column already bounds this; the old --vh cap (from
31768
+ // window.innerHeight) under-measured in iOS standalone and let
31769
+ // the composer's auto margins float it above the bottom.
31770
+ maxHeight: "100%",
31757
31771
  WebkitOverflowScrolling: "touch",
31758
31772
  overscrollBehavior: "contain",
31759
31773
  position: "relative",
@@ -31879,7 +31893,7 @@ var init_chat2 = __esm({
31879
31893
  display: "flex",
31880
31894
  flexDirection: "column",
31881
31895
  alignItems: "center",
31882
- margin: "auto",
31896
+ margin: "0 auto",
31883
31897
  width: "100vw",
31884
31898
  maxWidth: "768px"
31885
31899
  },