@burtson-labs/bandit-engine 2.0.126 → 2.0.128

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/{chat-Z3GRZ7GA.mjs → chat-MLDKHXUH.mjs} +5 -5
  2. package/dist/chat-provider.js +1 -1
  3. package/dist/chat-provider.js.map +1 -1
  4. package/dist/chat-provider.mjs +2 -2
  5. package/dist/{chunk-OLKDPUWL.mjs → chunk-BQW7DSJ6.mjs} +2 -2
  6. package/dist/{chunk-574ILQTT.mjs → chunk-FWFDOSRM.mjs} +2 -2
  7. package/dist/{chunk-JXFPCLEY.mjs → chunk-LQJ6OD7F.mjs} +332 -509
  8. package/dist/chunk-LQJ6OD7F.mjs.map +1 -0
  9. package/dist/{chunk-TQP3GUW5.mjs → chunk-N3TVVQVS.mjs} +3 -3
  10. package/dist/{chunk-6ONL4SRK.mjs → chunk-NLBZZP3B.mjs} +2 -2
  11. package/dist/{chunk-6ONL4SRK.mjs.map → chunk-NLBZZP3B.mjs.map} +1 -1
  12. package/dist/{chunk-SAQUEXYS.mjs → chunk-PU74BI6Y.mjs} +2 -2
  13. package/dist/{chunk-RKA3X3EY.mjs → chunk-QDTMVQWD.mjs} +23 -6
  14. package/dist/chunk-QDTMVQWD.mjs.map +1 -0
  15. package/dist/index.js +423 -581
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +7 -7
  18. package/dist/management/management.js +407 -565
  19. package/dist/management/management.js.map +1 -1
  20. package/dist/management/management.mjs +5 -5
  21. package/dist/modals/chat-modal/chat-modal.js +1 -1
  22. package/dist/modals/chat-modal/chat-modal.js.map +1 -1
  23. package/dist/modals/chat-modal/chat-modal.mjs +3 -3
  24. package/package.json +1 -1
  25. package/dist/chunk-JXFPCLEY.mjs.map +0 -1
  26. package/dist/chunk-RKA3X3EY.mjs.map +0 -1
  27. /package/dist/{chat-Z3GRZ7GA.mjs.map → chat-MLDKHXUH.mjs.map} +0 -0
  28. /package/dist/{chunk-OLKDPUWL.mjs.map → chunk-BQW7DSJ6.mjs.map} +0 -0
  29. /package/dist/{chunk-574ILQTT.mjs.map → chunk-FWFDOSRM.mjs.map} +0 -0
  30. /package/dist/{chunk-TQP3GUW5.mjs.map → chunk-N3TVVQVS.mjs.map} +0 -0
  31. /package/dist/{chunk-SAQUEXYS.mjs.map → chunk-PU74BI6Y.mjs.map} +0 -0
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-ONQMRE2G.mjs";
4
4
  import {
5
5
  StreamingMarkdown_default
6
- } from "./chunk-574ILQTT.mjs";
6
+ } from "./chunk-FWFDOSRM.mjs";
7
7
  import {
8
8
  useMCPToolsStore
9
9
  } from "./chunk-K2JGFKEB.mjs";
@@ -26,7 +26,6 @@ import {
26
26
  MicIcon,
27
27
  PanelLeftIcon,
28
28
  PsychologyIcon,
29
- RecordVoiceOverIcon,
30
29
  SignalWifi2BarIcon,
31
30
  WifiIcon,
32
31
  WifiOffIcon,
@@ -40,7 +39,7 @@ import {
40
39
  useNotificationService,
41
40
  useTTS,
42
41
  useVoiceStore
43
- } from "./chunk-OLKDPUWL.mjs";
42
+ } from "./chunk-BQW7DSJ6.mjs";
44
43
  import {
45
44
  brandingService_default,
46
45
  detectMessageMood,
@@ -64,7 +63,7 @@ import {
64
63
  useMemoryStore,
65
64
  useProjectStore,
66
65
  useVectorStore
67
- } from "./chunk-6ONL4SRK.mjs";
66
+ } from "./chunk-NLBZZP3B.mjs";
68
67
  import {
69
68
  indexedDBService_default,
70
69
  useModelStore,
@@ -1740,23 +1739,24 @@ ${sanitize(
1740
1739
  bgcolor: inputBackground,
1741
1740
  borderRadius: "24px",
1742
1741
  boxShadow: isMobile ? `0 0 0 1px ${theme.palette.mode === "dark" ? "#444" : "#eee"}` : "0 4px 20px rgba(0, 0, 0, 0.4)",
1743
- px: isMobile ? compactMobile ? 1 : 1.5 : 3,
1744
- pt: isMobile ? compactMobile ? 0.6 : 1 : 1,
1745
- pb: isMobile ? compactMobile ? 0.9 : 1.5 : 1.5,
1742
+ px: isMobile ? compactMobile ? 1 : 1.5 : 2,
1743
+ pt: isMobile ? compactMobile ? 0.6 : 1 : 0.75,
1744
+ pb: isMobile ? compactMobile ? 0.9 : 1.5 : 0.75,
1746
1745
  display: "flex",
1747
1746
  flexDirection: "column",
1748
- gap: isMobile ? compactMobile ? 0.75 : 1 : 1
1747
+ gap: isMobile ? compactMobile ? 0.75 : 1 : 0.5
1749
1748
  },
1750
1749
  children: [
1751
1750
  /* @__PURE__ */ jsxs6(
1752
1751
  Box6,
1753
1752
  {
1754
1753
  sx: {
1755
- display: "flex",
1754
+ display: fileInputs.length > 0 || pastedImages.length > 0 ? "flex" : "none",
1756
1755
  flexWrap: "wrap",
1757
1756
  gap: attachmentsGap,
1758
1757
  alignItems: "center",
1759
- flexDirection: "row"
1758
+ flexDirection: "row",
1759
+ pt: isMobile ? 0 : 0.5
1760
1760
  },
1761
1761
  children: [
1762
1762
  fileInputs.map((file, idx) => /* @__PURE__ */ jsxs6(
@@ -1880,7 +1880,7 @@ ${sanitize(
1880
1880
  ]
1881
1881
  }
1882
1882
  ),
1883
- /* @__PURE__ */ jsx9(
1883
+ isMobile && /* @__PURE__ */ jsx9(
1884
1884
  Box6,
1885
1885
  {
1886
1886
  sx: {
@@ -1893,8 +1893,8 @@ ${sanitize(
1893
1893
  {
1894
1894
  fullWidth: true,
1895
1895
  multiline: true,
1896
- maxRows: isMobile ? compactMobile ? 6 : 12 : 6,
1897
- placeholder: isIncognito ? "Incognito chat \u2014 not saved" : "What's on your mind?",
1896
+ maxRows: compactMobile ? 6 : 12,
1897
+ placeholder: isIncognito ? "Temporary chat \u2014 not saved" : "What's on your mind?",
1898
1898
  value: inputValue,
1899
1899
  onChange: (e) => setInputValue(e.target.value),
1900
1900
  onKeyDown: handleKeyPress,
@@ -1904,18 +1904,15 @@ ${sanitize(
1904
1904
  disableUnderline: true,
1905
1905
  sx: {
1906
1906
  flex: "1 1 auto",
1907
- maxHeight: isMobile ? compactMobile ? "120px" : "150px" : "none",
1907
+ maxHeight: compactMobile ? "120px" : "150px",
1908
1908
  overflowY: "auto",
1909
1909
  color: fileText,
1910
1910
  "& .MuiInputBase-inputMultiline": {
1911
- fontSize: isMobile ? compactMobile ? "0.95rem" : "1rem" : "1rem"
1911
+ fontSize: compactMobile ? "0.95rem" : "1rem"
1912
1912
  }
1913
1913
  }
1914
1914
  },
1915
- sx: {
1916
- flex: 1,
1917
- "& .MuiInputBase-root": {}
1918
- }
1915
+ sx: { flex: 1 }
1919
1916
  }
1920
1917
  )
1921
1918
  }
@@ -1926,9 +1923,9 @@ ${sanitize(
1926
1923
  sx: {
1927
1924
  display: "flex",
1928
1925
  justifyContent: "space-between",
1929
- alignItems: "center",
1926
+ alignItems: "flex-end",
1930
1927
  gap: isMobile ? 0.6 : 1,
1931
- mt: isMobile ? 0.5 : 1
1928
+ mt: isMobile ? 0.5 : 0
1932
1929
  },
1933
1930
  children: [
1934
1931
  /* @__PURE__ */ jsxs6(
@@ -2015,26 +2012,53 @@ ${sanitize(
2015
2012
  ]
2016
2013
  }
2017
2014
  ),
2018
- /* @__PURE__ */ jsx9(Box6, { sx: { display: "flex", alignItems: "center", gap: isMobile ? 0.6 : 1 }, children: /* @__PURE__ */ jsx9(Tooltip2, { title: isStreaming ? "Stop response" : "Send message", children: /* @__PURE__ */ jsx9("span", { children: /* @__PURE__ */ jsx9(
2019
- IconButton5,
2015
+ !isMobile && /* @__PURE__ */ jsx9(
2016
+ TextField2,
2020
2017
  {
2021
- onClick: isStreaming ? onStop || (() => {
2022
- }) : handleSubmit,
2023
- disabled: (isStreaming ? false : isSubmitting) || !isStreaming && !inputValue.trim() && pastedImages.length === 0 && fileInputs.length === 0,
2024
- sx: {
2025
- bgcolor: sendButtonBackground,
2026
- color: sendButtonColor,
2027
- borderRadius: "50%",
2028
- width: sendIconSize,
2029
- height: sendIconSize,
2030
- boxShadow: sendButtonShadow,
2031
- transition: "background-color 0.2s ease, box-shadow 0.2s ease",
2032
- "&:hover": { bgcolor: sendButtonHover },
2033
- "&.Mui-disabled": { opacity: 0.5 }
2018
+ fullWidth: true,
2019
+ multiline: true,
2020
+ maxRows: 6,
2021
+ placeholder: isIncognito ? "Temporary chat \u2014 not saved" : "What's on your mind?",
2022
+ value: inputValue,
2023
+ onChange: (e) => setInputValue(e.target.value),
2024
+ onKeyDown: handleKeyPress,
2025
+ inputRef,
2026
+ variant: "standard",
2027
+ InputProps: {
2028
+ disableUnderline: true,
2029
+ sx: {
2030
+ color: fileText,
2031
+ maxHeight: "160px",
2032
+ overflowY: "auto",
2033
+ "& .MuiInputBase-inputMultiline": { fontSize: "1rem" }
2034
+ }
2034
2035
  },
2035
- children: isStreaming ? /* @__PURE__ */ jsx9(CloseIcon, { fontSize: "small" }) : /* @__PURE__ */ jsx9(ArrowUpwardIcon, { fontSize: "small" })
2036
+ sx: { flex: 1, alignSelf: "center", mx: 0.5 }
2036
2037
  }
2037
- ) }) }) })
2038
+ ),
2039
+ /* @__PURE__ */ jsxs6(Box6, { sx: { display: "flex", alignItems: "center", gap: isMobile ? 0.6 : 1 }, children: [
2040
+ !isMobile && /* @__PURE__ */ jsx9(engine_picker_default, {}),
2041
+ /* @__PURE__ */ jsx9(Tooltip2, { title: isStreaming ? "Stop response" : "Send message", children: /* @__PURE__ */ jsx9("span", { children: /* @__PURE__ */ jsx9(
2042
+ IconButton5,
2043
+ {
2044
+ onClick: isStreaming ? onStop || (() => {
2045
+ }) : handleSubmit,
2046
+ disabled: (isStreaming ? false : isSubmitting) || !isStreaming && !inputValue.trim() && pastedImages.length === 0 && fileInputs.length === 0,
2047
+ sx: {
2048
+ bgcolor: sendButtonBackground,
2049
+ color: sendButtonColor,
2050
+ borderRadius: "50%",
2051
+ width: sendIconSize,
2052
+ height: sendIconSize,
2053
+ boxShadow: sendButtonShadow,
2054
+ transition: "background-color 0.2s ease, box-shadow 0.2s ease",
2055
+ "&:hover": { bgcolor: sendButtonHover },
2056
+ "&.Mui-disabled": { opacity: 0.5 }
2057
+ },
2058
+ children: isStreaming ? /* @__PURE__ */ jsx9(CloseIcon, { fontSize: "small" }) : /* @__PURE__ */ jsx9(ArrowUpwardIcon, { fontSize: "small" })
2059
+ }
2060
+ ) }) })
2061
+ ] })
2038
2062
  ]
2039
2063
  }
2040
2064
  ),
@@ -2081,7 +2105,7 @@ ${sanitize(
2081
2105
  ]
2082
2106
  }
2083
2107
  ),
2084
- !isMobile && /* @__PURE__ */ jsxs6(
2108
+ (!isMobile || isIncognito) && /* @__PURE__ */ jsx9(
2085
2109
  Typography3,
2086
2110
  {
2087
2111
  variant: "caption",
@@ -2093,10 +2117,7 @@ ${sanitize(
2093
2117
  textAlign: "center",
2094
2118
  pointerEvents: "none"
2095
2119
  },
2096
- children: [
2097
- brandingText || "BanditAI",
2098
- " may be wrong - double-check important info."
2099
- ]
2120
+ children: isIncognito ? "Temporary chats aren't saved to history, synced, or added to memory." : `${brandingText || "BanditAI"} may be wrong - double-check important info.`
2100
2121
  }
2101
2122
  )
2102
2123
  ]
@@ -2117,8 +2138,9 @@ var chat_input_default = ChatInput;
2117
2138
 
2118
2139
  // src/chat/ask-user-card.tsx
2119
2140
  import { useEffect as useEffect5, useState as useState7 } from "react";
2120
- import { Box as Box7, Paper, Typography as Typography4, Button as Button2, TextField as TextField3, Chip, Stack } from "@mui/material";
2141
+ import { Box as Box7, Paper, Typography as Typography4, Button as Button2, TextField as TextField3, Chip, Grow } from "@mui/material";
2121
2142
  import { useTheme as useTheme7, alpha as alpha4 } from "@mui/material/styles";
2143
+ import { CircleHelp as QuestionIcon, Check as CheckIcon3 } from "lucide-react";
2122
2144
 
2123
2145
  // src/store/askUserStore.ts
2124
2146
  import { create as create3 } from "zustand";
@@ -2209,57 +2231,142 @@ var AskUserCard = () => {
2209
2231
  });
2210
2232
  submit(final);
2211
2233
  };
2212
- return /* @__PURE__ */ jsx10(Box7, { sx: { width: "100%", display: "flex", justifyContent: "center", px: { xs: 1, sm: 2 }, mb: 1.5 }, children: /* @__PURE__ */ jsxs7(
2234
+ const isSingleQuestion = pending.questions.length === 1;
2235
+ const handleOptionTap = (qid, label) => {
2236
+ setFreeform((p) => ({ ...p, [qid]: "" }));
2237
+ if (isSingleQuestion) {
2238
+ submit({ [qid]: label });
2239
+ return;
2240
+ }
2241
+ setSelected((p) => ({ ...p, [qid]: label }));
2242
+ };
2243
+ return /* @__PURE__ */ jsx10(Grow, { in: true, timeout: 300, children: /* @__PURE__ */ jsx10(Box7, { sx: { width: "100%", display: "flex", justifyContent: "center", px: { xs: 1, sm: 2 }, mb: 1.5 }, children: /* @__PURE__ */ jsxs7(
2213
2244
  Paper,
2214
2245
  {
2215
2246
  elevation: 0,
2216
2247
  sx: {
2217
2248
  width: "100%",
2218
2249
  maxWidth: 760,
2219
- p: { xs: 1.75, sm: 2.25 },
2220
- borderRadius: 2,
2221
- border: `1px solid ${alpha4(theme.palette.primary.main, 0.45)}`,
2222
- bgcolor: alpha4(theme.palette.primary.main, 0.06)
2250
+ p: { xs: 2, sm: 2.5 },
2251
+ borderRadius: 3,
2252
+ border: `1px solid ${theme.palette.divider}`,
2253
+ bgcolor: theme.palette.background.paper,
2254
+ boxShadow: `0 8px 32px ${alpha4(theme.palette.common.black, theme.palette.mode === "dark" ? 0.35 : 0.1)}`
2223
2255
  },
2224
2256
  children: [
2225
- /* @__PURE__ */ jsx10(Typography4, { variant: "caption", sx: { color: theme.palette.primary.main, fontWeight: 700, letterSpacing: 0.4 }, children: "BANDIT NEEDS A QUICK DECISION" }),
2226
- pending.questions.map((q) => /* @__PURE__ */ jsxs7(Box7, { sx: { mt: 1.5 }, children: [
2227
- q.header && /* @__PURE__ */ jsx10(Chip, { label: q.header, size: "small", sx: { mb: 0.75, fontWeight: 600 }, color: "primary", variant: "outlined" }),
2228
- /* @__PURE__ */ jsx10(Typography4, { sx: { fontWeight: 600, color: theme.palette.text.primary, mb: 1 }, children: q.question }),
2229
- q.options && q.options.length > 0 && /* @__PURE__ */ jsx10(Stack, { spacing: 1, children: q.options.map((opt) => {
2230
- const isSel = selected[q.id] === opt.label && !freeform[q.id]?.trim();
2231
- return /* @__PURE__ */ jsx10(
2232
- Button2,
2257
+ /* @__PURE__ */ jsxs7(Box7, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 0.5 }, children: [
2258
+ /* @__PURE__ */ jsx10(
2259
+ Box7,
2260
+ {
2261
+ sx: {
2262
+ width: 26,
2263
+ height: 26,
2264
+ borderRadius: "50%",
2265
+ display: "flex",
2266
+ alignItems: "center",
2267
+ justifyContent: "center",
2268
+ bgcolor: alpha4(theme.palette.primary.main, 0.12),
2269
+ color: theme.palette.primary.main,
2270
+ flexShrink: 0
2271
+ },
2272
+ children: /* @__PURE__ */ jsx10(QuestionIcon, { size: 16 })
2273
+ }
2274
+ ),
2275
+ /* @__PURE__ */ jsx10(Typography4, { variant: "body2", sx: { color: theme.palette.text.secondary, fontWeight: 600 }, children: "Quick question before I continue" })
2276
+ ] }),
2277
+ pending.questions.map((q) => /* @__PURE__ */ jsxs7(Box7, { sx: { mt: 1.75 }, children: [
2278
+ /* @__PURE__ */ jsxs7(Box7, { sx: { display: "flex", alignItems: "baseline", gap: 1, flexWrap: "wrap", mb: 1.25 }, children: [
2279
+ /* @__PURE__ */ jsx10(Typography4, { sx: { fontWeight: 600, fontSize: "1.02rem", color: theme.palette.text.primary }, children: q.question }),
2280
+ q.header && /* @__PURE__ */ jsx10(
2281
+ Chip,
2233
2282
  {
2234
- onClick: () => {
2235
- setSelected((p) => ({ ...p, [q.id]: opt.label }));
2236
- setFreeform((p) => ({ ...p, [q.id]: "" }));
2237
- },
2238
- variant: isSel ? "contained" : "outlined",
2239
- color: "primary",
2283
+ label: q.header,
2284
+ size: "small",
2240
2285
  sx: {
2241
- justifyContent: "flex-start",
2242
- textAlign: "left",
2243
- textTransform: "none",
2244
- py: 1,
2245
- px: 1.5,
2246
- borderColor: alpha4(theme.palette.primary.main, 0.4)
2247
- },
2248
- children: /* @__PURE__ */ jsxs7(Box7, { children: [
2249
- /* @__PURE__ */ jsx10(Typography4, { sx: { fontWeight: 600, lineHeight: 1.3 }, children: opt.label }),
2250
- opt.description && /* @__PURE__ */ jsx10(
2251
- Typography4,
2252
- {
2253
- variant: "caption",
2254
- sx: { color: isSel ? alpha4("#fff", 0.85) : theme.palette.text.secondary, display: "block" },
2255
- children: opt.description
2256
- }
2257
- )
2258
- ] })
2286
+ height: 20,
2287
+ fontSize: "0.7rem",
2288
+ fontWeight: 600,
2289
+ color: theme.palette.text.secondary,
2290
+ bgcolor: alpha4(theme.palette.text.primary, 0.06)
2291
+ }
2292
+ }
2293
+ )
2294
+ ] }),
2295
+ q.options && q.options.length > 0 && /* @__PURE__ */ jsx10(
2296
+ Box7,
2297
+ {
2298
+ sx: {
2299
+ display: "grid",
2300
+ gridTemplateColumns: { xs: "1fr", sm: q.options.length > 1 ? "1fr 1fr" : "1fr" },
2301
+ gap: 1
2259
2302
  },
2260
- opt.label
2261
- );
2262
- }) }),
2303
+ children: q.options.map((opt) => {
2304
+ const isSel = selected[q.id] === opt.label && !freeform[q.id]?.trim();
2305
+ return /* @__PURE__ */ jsxs7(
2306
+ Box7,
2307
+ {
2308
+ component: "button",
2309
+ type: "button",
2310
+ onClick: () => handleOptionTap(q.id, opt.label),
2311
+ sx: {
2312
+ font: "inherit",
2313
+ textAlign: "left",
2314
+ cursor: "pointer",
2315
+ display: "flex",
2316
+ alignItems: "flex-start",
2317
+ gap: 1,
2318
+ px: 1.5,
2319
+ py: 1.25,
2320
+ borderRadius: 2,
2321
+ border: `1.5px solid ${isSel ? theme.palette.primary.main : theme.palette.divider}`,
2322
+ bgcolor: isSel ? alpha4(theme.palette.primary.main, 0.08) : "transparent",
2323
+ color: "inherit",
2324
+ transition: "border-color 0.15s ease, background-color 0.15s ease, transform 0.1s ease",
2325
+ "&:hover": {
2326
+ borderColor: theme.palette.primary.main,
2327
+ bgcolor: alpha4(theme.palette.primary.main, 0.05)
2328
+ },
2329
+ "&:active": { transform: "scale(0.99)" }
2330
+ },
2331
+ children: [
2332
+ /* @__PURE__ */ jsx10(
2333
+ Box7,
2334
+ {
2335
+ sx: {
2336
+ width: 18,
2337
+ height: 18,
2338
+ mt: "2px",
2339
+ borderRadius: "50%",
2340
+ flexShrink: 0,
2341
+ display: "flex",
2342
+ alignItems: "center",
2343
+ justifyContent: "center",
2344
+ border: `1.5px solid ${isSel ? theme.palette.primary.main : alpha4(theme.palette.text.secondary, 0.5)}`,
2345
+ bgcolor: isSel ? theme.palette.primary.main : "transparent",
2346
+ color: theme.palette.getContrastText(theme.palette.primary.main),
2347
+ transition: "all 0.15s ease"
2348
+ },
2349
+ children: isSel && /* @__PURE__ */ jsx10(CheckIcon3, { size: 12, strokeWidth: 3 })
2350
+ }
2351
+ ),
2352
+ /* @__PURE__ */ jsxs7(Box7, { sx: { minWidth: 0 }, children: [
2353
+ /* @__PURE__ */ jsx10(Typography4, { sx: { fontWeight: 600, lineHeight: 1.35, fontSize: "0.92rem" }, children: opt.label }),
2354
+ opt.description && /* @__PURE__ */ jsx10(
2355
+ Typography4,
2356
+ {
2357
+ variant: "caption",
2358
+ sx: { color: theme.palette.text.secondary, display: "block", mt: 0.25 },
2359
+ children: opt.description
2360
+ }
2361
+ )
2362
+ ] })
2363
+ ]
2364
+ },
2365
+ opt.label
2366
+ );
2367
+ })
2368
+ }
2369
+ ),
2263
2370
  q.allowFreeform !== false && /* @__PURE__ */ jsx10(
2264
2371
  TextField3,
2265
2372
  {
@@ -2268,17 +2375,45 @@ var AskUserCard = () => {
2268
2375
  placeholder: q.options && q.options.length ? "Or type your own answer\u2026" : "Type your answer\u2026",
2269
2376
  value: freeform[q.id] ?? "",
2270
2377
  onChange: (e) => setFreeform((p) => ({ ...p, [q.id]: e.target.value })),
2271
- sx: { mt: q.options && q.options.length ? 1.25 : 0 }
2378
+ onKeyDown: (e) => {
2379
+ if (e.key === "Enter" && !e.shiftKey && answerFor(q.id)) {
2380
+ e.preventDefault();
2381
+ if (allAnswered) handleSubmit();
2382
+ }
2383
+ },
2384
+ sx: {
2385
+ mt: q.options && q.options.length ? 1.25 : 0,
2386
+ "& .MuiOutlinedInput-root": { borderRadius: 2 }
2387
+ }
2272
2388
  }
2273
2389
  )
2274
2390
  ] }, q.id)),
2275
- /* @__PURE__ */ jsxs7(Box7, { sx: { display: "flex", justifyContent: "flex-end", gap: 1, mt: 2 }, children: [
2276
- /* @__PURE__ */ jsx10(Button2, { onClick: cancel, color: "inherit", sx: { textTransform: "none", color: theme.palette.text.secondary }, children: "Skip" }),
2277
- /* @__PURE__ */ jsx10(Button2, { onClick: handleSubmit, disabled: !allAnswered, variant: "contained", sx: { textTransform: "none" }, children: "Submit" })
2391
+ /* @__PURE__ */ jsxs7(Box7, { sx: { display: "flex", alignItems: "center", justifyContent: "flex-end", gap: 1, mt: 2 }, children: [
2392
+ /* @__PURE__ */ jsx10(
2393
+ Button2,
2394
+ {
2395
+ onClick: cancel,
2396
+ color: "inherit",
2397
+ size: "small",
2398
+ sx: { textTransform: "none", color: theme.palette.text.secondary },
2399
+ children: "Skip \u2014 use your best judgment"
2400
+ }
2401
+ ),
2402
+ (!isSingleQuestion || Object.values(freeform).some((v) => v.trim())) && /* @__PURE__ */ jsx10(
2403
+ Button2,
2404
+ {
2405
+ onClick: handleSubmit,
2406
+ disabled: !allAnswered,
2407
+ variant: "contained",
2408
+ size: "small",
2409
+ sx: { textTransform: "none", borderRadius: 999, px: 2.5 },
2410
+ children: "Answer"
2411
+ }
2412
+ )
2278
2413
  ] })
2279
2414
  ]
2280
2415
  }
2281
- ) });
2416
+ ) }) });
2282
2417
  };
2283
2418
  var ask_user_card_default = AskUserCard;
2284
2419
 
@@ -4187,14 +4322,14 @@ TOOL USAGE PROTOCOL (conservative approach)
4187
4322
  * web_fetch() - to read the FULL contents of a specific URL you already have. Reach for this when the user wants to "tell me more", "go deeper", "read/open that article", or asks for details about a specific source, link, or article from an EARLIER answer: take that item's URL from the previous Sources list in this conversation and fetch it, then answer from the page's actual content (not just the prior summary)
4188
4323
  * image_generation() - ONLY when explicitly asked to create or generate an image
4189
4324
  * create_file({"content": "...", "filename": "report.docx", "format": "docx"}) - when the user asks for a downloadable FILE (a document, spreadsheet, slides, markdown, code, etc.) or to "export"/"download"/"save" something. Formats: md, txt, csv, json, html, xml, yaml, docx, pptx. PDF is NOT a supported format \u2014 if the user asks for a PDF, create a docx instead. For docx/pptx write well-structured Markdown (use "## " headings to start each slide for pptx). It returns a temporary download link \u2014 ALWAYS tell the user the file expires (~1 hour). If it is unclear whether they want it shown inline vs. as a downloadable file, use ask_user first.
4190
- * ask_user({"questions": [{"question": "...", "header": "Format", "options": [{"label": "Inline (Recommended)"}, {"label": "Download a file"}]}]}) - when you are genuinely BLOCKED on a decision that is the USER's to make and cannot resolve from the request, context, or sensible defaults (e.g. show content inline vs. let them download it, which format/option they want). Renders clickable options the user answers in one step \u2014 better than asking in prose and ending your turn. Give 1-4 questions, each with 2-4 options; if one is clearly best, list it first and append " (Recommended)". The user may also type their own answer; act on it directly.
4325
+ * ask_user({"questions": [{"question": "...", "header": "Format", "options": [{"label": "Inline (Recommended)"}, {"label": "Download a file"}]}]}) - when the request is AMBIGUOUS or missing a detail you need to do a good job (unclear scope, audience, format, tone, which of several interpretations they meant), or you are blocked on a decision that is the user's to make and cannot resolve from the request, context, or sensible defaults. Renders clickable options the user answers in one step \u2014 ALWAYS prefer this over asking a clarifying question in prose and ending your turn. Give 1-4 questions, each with 2-4 short options; if one is clearly best, list it first and append " (Recommended)". The user may also type their own answer; act on it directly. Don't overuse it \u2014 when a sensible default exists, take it and note the assumption instead.
4191
4326
  - For general questions about concepts, definitions, explanations, or how-to topics, use your built-in knowledge WITHOUT calling tools.
4192
4327
  - Examples of what NOT to use tools for: "who are you?", "what is React?", "explain machine learning", "how does X work?", general programming questions.
4193
4328
  - When a tool is truly needed, call exactly ONE tool that best matches the request.
4194
4329
  - Begin tool usage with a fenced code block: \`\`\`tool_code
4195
4330
  functionName({"param": "value"})
4196
4331
  \`\`\`
4197
- - If you cannot answer with your knowledge and context, and no suitable tool exists, ask a clarifying question.
4332
+ - If you cannot answer with your knowledge and context, and no suitable tool exists, use ask_user to ask a clarifying question with clickable options.
4198
4333
 
4199
4334
  Examples of appropriate tool usage:
4200
4335
 
@@ -5176,8 +5311,6 @@ import { useEffect as useEffect13, useRef as useRef11, useState as useState16 }
5176
5311
  import {
5177
5312
  Box as Box15,
5178
5313
  IconButton as IconButton12,
5179
- Menu as Menu7,
5180
- MenuItem as MenuItem7,
5181
5314
  Tooltip as Tooltip5,
5182
5315
  useMediaQuery as useMediaQuery6,
5183
5316
  useTheme as useTheme15,
@@ -6459,7 +6592,7 @@ import {
6459
6592
  TextField as TextField6,
6460
6593
  alpha as alpha7
6461
6594
  } from "@mui/material";
6462
- import { ChevronDown as ExpandMoreIcon2, ChevronUp as ExpandLessIcon, Plus as AddIcon3, Folder as FolderIcon3, FolderOpen as FolderOpenIcon, Inbox as InboxIcon2, X as CloseIcon5, Check as CheckIcon3 } from "lucide-react";
6595
+ import { ChevronDown as ExpandMoreIcon2, ChevronUp as ExpandLessIcon, Plus as AddIcon3, Folder as FolderIcon3, FolderOpen as FolderOpenIcon, Inbox as InboxIcon2, X as CloseIcon5, Check as CheckIcon4 } from "lucide-react";
6463
6596
  import { useTheme as useTheme12 } from "@mui/material/styles";
6464
6597
  import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
6465
6598
  var ProjectHeader = ({
@@ -6693,7 +6826,7 @@ var ProjectHeader = ({
6693
6826
  commitRename();
6694
6827
  },
6695
6828
  sx: { color: theme.palette.success.main },
6696
- children: /* @__PURE__ */ jsx15(CheckIcon3, { size: 16 })
6829
+ children: /* @__PURE__ */ jsx15(CheckIcon4, { size: 16 })
6697
6830
  }
6698
6831
  ) })
6699
6832
  ] }),
@@ -9027,13 +9160,13 @@ var ChatAppBar = ({
9027
9160
  /* @__PURE__ */ jsx18(
9028
9161
  Tooltip5,
9029
9162
  {
9030
- title: isIncognitoActive ? "End incognito chat" : "Start incognito chat \u2014 not saved",
9163
+ title: isIncognitoActive ? "End temporary chat" : "Temporary chat \u2014 not saved anywhere",
9031
9164
  arrow: true,
9032
9165
  children: /* @__PURE__ */ jsx18(
9033
9166
  IconButton12,
9034
9167
  {
9035
9168
  onClick: toggleIncognito,
9036
- "aria-label": isIncognitoActive ? "End incognito chat" : "Start incognito chat",
9169
+ "aria-label": isIncognitoActive ? "End temporary chat" : "Start temporary chat",
9037
9170
  "aria-pressed": isIncognitoActive,
9038
9171
  sx: {
9039
9172
  width: 44,
@@ -9132,35 +9265,11 @@ var ChatAppBar = ({
9132
9265
  "aria-label": "Create new conversation",
9133
9266
  children: /* @__PURE__ */ jsx18(AddIcon, {})
9134
9267
  }
9135
- ) }),
9136
- /* @__PURE__ */ jsx18(
9137
- Tooltip5,
9138
- {
9139
- title: isIncognitoActive ? "End incognito chat" : "Start incognito chat \u2014 not saved",
9140
- arrow: true,
9141
- children: /* @__PURE__ */ jsx18(
9142
- IconButton12,
9143
- {
9144
- onClick: toggleIncognito,
9145
- "aria-label": isIncognitoActive ? "End incognito chat" : "Start incognito chat",
9146
- "aria-pressed": isIncognitoActive,
9147
- sx: {
9148
- ...pillButtonStyles,
9149
- ...isIncognitoActive && {
9150
- bgcolor: theme.palette.text.primary,
9151
- color: theme.palette.getContrastText(theme.palette.text.primary),
9152
- "&:hover": { bgcolor: theme.palette.text.primary }
9153
- }
9154
- },
9155
- children: /* @__PURE__ */ jsx18(GhostIcon, {})
9156
- }
9157
- )
9158
- }
9159
- )
9268
+ ) })
9160
9269
  ]
9161
9270
  }
9162
9271
  ),
9163
- !isMobile && /* @__PURE__ */ jsxs15(
9272
+ !isMobile && /* @__PURE__ */ jsx18(
9164
9273
  Box15,
9165
9274
  {
9166
9275
  sx: {
@@ -9180,368 +9289,30 @@ var ChatAppBar = ({
9180
9289
  boxShadow: theme.palette.mode === "dark" ? "0 6px 20px rgba(0,0,0,0.4)" : "0 6px 20px rgba(0,0,0,0.15)"
9181
9290
  }
9182
9291
  },
9183
- children: [
9184
- /* @__PURE__ */ jsx18(Tooltip5, { title: `Current AI: ${selectedModel.replace("Bandit-", "")}`, arrow: true, children: /* @__PURE__ */ jsx18(
9185
- IconButton12,
9186
- {
9187
- onClick: (e) => setModelAnchorEl(e.currentTarget),
9188
- sx: {
9189
- ...pillButtonStyles,
9190
- "&:hover": {
9191
- ...pillButtonStyles["&:hover"],
9192
- "& .MuiAvatar-root": {
9193
- transform: "scale(1.1)",
9194
- filter: "brightness(2) saturate(1.2)"
9195
- }
9196
- }
9197
- },
9198
- "aria-label": `Change AI personality. Currently using ${selectedModel}`,
9199
- children: /* @__PURE__ */ jsx18(
9200
- Avatar8,
9201
- {
9202
- src: currentAvatar,
9203
- alt: selectedModel,
9204
- sx: {
9205
- width: "36px",
9206
- height: "36px",
9207
- filter: "brightness(1.7)",
9208
- transition: "all 0.2s ease-in-out",
9209
- border: `2px solid ${theme.palette.primary.main}20`
9210
- },
9211
- className: "MuiAvatar-root"
9212
- }
9213
- )
9214
- }
9215
- ) }),
9216
- /* @__PURE__ */ jsx18(Tooltip5, { title: `Engine \xB7 ${engineDisplay}`, arrow: true, children: /* @__PURE__ */ jsx18(
9217
- IconButton12,
9218
- {
9219
- onClick: (e) => setEngineAnchorEl(e.currentTarget),
9220
- sx: pillButtonStyles,
9221
- "aria-label": `Change base model (engine). Currently ${engineDisplay}`,
9222
- children: /* @__PURE__ */ jsx18(AutoAwesomeIcon, { fontSize: "small" })
9223
- }
9224
- ) }),
9225
- /* @__PURE__ */ jsxs15(
9226
- Menu7,
9227
- {
9228
- anchorEl: engineAnchorEl,
9229
- open: Boolean(engineAnchorEl),
9230
- onClose: () => setEngineAnchorEl(null),
9231
- transformOrigin: { horizontal: "right", vertical: "top" },
9232
- anchorOrigin: { horizontal: "right", vertical: "bottom" },
9233
- children: [
9234
- /* @__PURE__ */ jsx18(Typography12, { variant: "overline", sx: { px: 2, color: theme.palette.text.secondary }, children: "Engine \xB7 base model" }),
9235
- engines.length === 0 && /* @__PURE__ */ jsx18(MenuItem7, { disabled: true, children: /* @__PURE__ */ jsx18(Typography12, { variant: "body2", children: "No engines available" }) }),
9236
- engines.map((engine) => {
9237
- const badges = [
9238
- engine.vision && "vision",
9239
- engine.tools && "tools",
9240
- engine.thinking && "thinking",
9241
- engine.cloud && "cloud"
9242
- ].filter(Boolean);
9243
- const isGated = engine.cloud && !frontierEligible;
9244
- return /* @__PURE__ */ jsxs15(
9245
- MenuItem7,
9246
- {
9247
- selected: engine.id === resolvedEngineId,
9248
- disabled: !engine.available || isGated,
9249
- onClick: () => {
9250
- if (isGated) return;
9251
- useEngineStore.getState().setSelectedEngine(engine.id);
9252
- setEngineAnchorEl(null);
9253
- },
9254
- sx: {
9255
- display: "flex",
9256
- flexDirection: "column",
9257
- alignItems: "flex-start",
9258
- gap: 0.5,
9259
- py: 1,
9260
- px: 2,
9261
- maxWidth: 360,
9262
- whiteSpace: "normal",
9263
- // Keep gated rows readable (MUI disabled dims to ~38%) so the
9264
- // upsell stays legible.
9265
- ...isGated ? { opacity: 1, "&.Mui-disabled": { opacity: 1 } } : {}
9266
- },
9267
- children: [
9268
- /* @__PURE__ */ jsxs15(Box15, { sx: { display: "flex", alignItems: "center", gap: 1, width: "100%" }, children: [
9269
- isGated && /* @__PURE__ */ jsx18(
9270
- LockIcon,
9271
- {
9272
- fontSize: "small",
9273
- sx: { fontSize: "0.95rem", color: theme.palette.text.secondary }
9274
- }
9275
- ),
9276
- /* @__PURE__ */ jsx18(
9277
- Typography12,
9278
- {
9279
- variant: "body2",
9280
- sx: {
9281
- fontWeight: 600,
9282
- flex: 1,
9283
- color: isGated ? theme.palette.text.secondary : void 0
9284
- },
9285
- children: cleanEngineName(engine.displayName)
9286
- }
9287
- ),
9288
- engine.id === resolvedEngineId && !isGated && /* @__PURE__ */ jsx18(Box15, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: theme.palette.primary.main } })
9289
- ] }),
9290
- /* @__PURE__ */ jsx18(Typography12, { variant: "caption", sx: { color: theme.palette.text.secondary }, children: isGated ? "Premium engine \u2014 available on a paid plan." : engine.available ? engine.description : engine.unavailableReason || "Unavailable" }),
9291
- isGated && /* @__PURE__ */ jsx18(
9292
- Button9,
9293
- {
9294
- size: "small",
9295
- variant: "text",
9296
- startIcon: /* @__PURE__ */ jsx18(LockIcon, { sx: { fontSize: "0.85rem" } }),
9297
- onClick: (e) => {
9298
- e.stopPropagation();
9299
- setEngineAnchorEl(null);
9300
- safeNavigate(plansPath);
9301
- },
9302
- sx: {
9303
- mt: 0.25,
9304
- px: 0.75,
9305
- py: 0.1,
9306
- minWidth: 0,
9307
- textTransform: "none",
9308
- fontSize: "0.7rem",
9309
- fontWeight: 600,
9310
- color: theme.palette.primary.main,
9311
- // Re-enable pointer events the disabled MenuItem strips.
9312
- pointerEvents: "auto"
9313
- },
9314
- children: "Upgrade to unlock"
9315
- }
9316
- ),
9317
- badges.length > 0 && /* @__PURE__ */ jsx18(Box15, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap", mt: 0.25 }, children: badges.map((b) => /* @__PURE__ */ jsx18(
9318
- Box15,
9319
- {
9320
- sx: {
9321
- fontSize: "0.65rem",
9322
- px: 0.75,
9323
- py: 0.1,
9324
- borderRadius: 1,
9325
- bgcolor: theme.palette.primary.main + "22",
9326
- color: theme.palette.primary.main
9327
- },
9328
- children: b
9329
- },
9330
- b
9331
- )) })
9332
- ]
9333
- },
9334
- engine.id
9335
- );
9336
- })
9337
- ]
9338
- }
9339
- ),
9340
- /* @__PURE__ */ jsx18(
9341
- Menu7,
9342
- {
9343
- anchorEl: modelAnchorEl,
9344
- open: Boolean(modelAnchorEl),
9345
- onClose: () => setModelAnchorEl(null),
9346
- transformOrigin: { horizontal: "right", vertical: "top" },
9347
- anchorOrigin: { horizontal: "right", vertical: "bottom" },
9348
- PaperProps: {
9349
- sx: {
9350
- bgcolor: menuBackground,
9351
- color: menuText,
9352
- fontSize: "0.875rem",
9353
- zIndex: 2e4,
9354
- borderRadius: 2,
9355
- border: `1px solid ${border}`,
9356
- boxShadow: theme.palette.mode === "dark" ? "0 8px 32px rgba(0,0,0,0.5)" : "0 8px 32px rgba(0,0,0,0.2)",
9357
- minWidth: 200,
9358
- "& .MuiMenuItem-root": {
9359
- transition: "all 0.15s ease-in-out",
9360
- borderRadius: "6px",
9361
- margin: "2px 4px",
9362
- "&:hover": {
9363
- bgcolor: theme.palette.mode === "dark" ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.04)",
9364
- transform: "translateX(2px)"
9365
- },
9366
- "&.Mui-selected": {
9367
- bgcolor: theme.palette.primary.main + "20",
9368
- color: theme.palette.primary.main,
9369
- "&:hover": {
9370
- bgcolor: theme.palette.primary.main + "30"
9371
- }
9372
- }
9373
- }
9374
- }
9375
- },
9376
- children: availableModels.map((model) => /* @__PURE__ */ jsxs15(
9377
- MenuItem7,
9378
- {
9379
- selected: model.name === selectedModel,
9380
- onClick: () => {
9381
- if (!currentConversation?.history.length || currentConversation?.history.length === 0) {
9382
- handleModelChange(model.name);
9383
- useModelStore.getState().setSelectedModel(model.name);
9384
- (async () => {
9385
- try {
9386
- const storeConfigs = [{ name: "config", keyPath: "id" }];
9387
- const current = await indexedDBService_default.get(
9388
- "banditConfig",
9389
- 1,
9390
- "config",
9391
- "main",
9392
- storeConfigs
9393
- );
9394
- const updated = {
9395
- ...current ?? {},
9396
- id: "main",
9397
- model: {
9398
- ...current?.model || {},
9399
- name: model.name,
9400
- selectedModel: model.name
9401
- }
9402
- };
9403
- await indexedDBService_default.put("banditConfig", 1, "config", updated, storeConfigs);
9404
- } catch (err) {
9405
- debugLogger.error("Failed to persist selectedModel to IndexedDB", { error: err });
9406
- }
9407
- })();
9408
- setModelAnchorEl(null);
9409
- return;
9410
- }
9411
- setPendingModel(model.name);
9412
- setConfirmModelChangeOpen(true);
9413
- setModelAnchorEl(null);
9414
- },
9415
- sx: {
9416
- display: "flex",
9417
- alignItems: "center",
9418
- gap: 1.5,
9419
- minHeight: 48,
9420
- px: 2
9421
- },
9422
- children: [
9423
- /* @__PURE__ */ jsx18(
9424
- Avatar8,
9425
- {
9426
- src: model.avatarBase64 || modelAvatars[model.name] || banditHead,
9427
- alt: model.name,
9428
- sx: {
9429
- width: 28,
9430
- height: 28,
9431
- filter: "brightness(1.7)",
9432
- transition: "all 0.2s ease-in-out"
9433
- }
9434
- }
9435
- ),
9436
- /* @__PURE__ */ jsxs15(Box15, { sx: { flex: 1 }, children: [
9437
- /* @__PURE__ */ jsx18(Typography12, { variant: "body2", sx: { fontWeight: 500 }, children: model.name.replace("Bandit-", "") }),
9438
- /* @__PURE__ */ jsx18(Typography12, { variant: "caption", sx: { color: theme.palette.text.secondary, display: "block" }, children: model.name === selectedModel ? "Currently active" : "Switch to this AI" })
9439
- ] }),
9440
- model.name === selectedModel && /* @__PURE__ */ jsx18(
9441
- Box15,
9442
- {
9443
- sx: {
9444
- width: 8,
9445
- height: 8,
9446
- borderRadius: "50%",
9447
- bgcolor: theme.palette.primary.main
9448
- }
9449
- }
9450
- )
9451
- ]
9452
- },
9453
- model.name
9454
- ))
9455
- }
9456
- ),
9457
- isTTSAvailable && /* @__PURE__ */ jsxs15(Fragment10, { children: [
9458
- /* @__PURE__ */ jsx18(Tooltip5, { title: `Voice: ${selectedVoice ? toTitleCase(selectedVoice.split("-")[1]) : "Default"}`, arrow: true, children: /* @__PURE__ */ jsx18(
9292
+ children: /* @__PURE__ */ jsx18(
9293
+ Tooltip5,
9294
+ {
9295
+ title: isIncognitoActive ? "End temporary chat" : "Temporary chat \u2014 not saved anywhere",
9296
+ arrow: true,
9297
+ children: /* @__PURE__ */ jsx18(
9459
9298
  IconButton12,
9460
9299
  {
9461
- onClick: (e) => setVoiceAnchorEl(e.currentTarget),
9300
+ onClick: toggleIncognito,
9301
+ "aria-label": isIncognitoActive ? "End temporary chat" : "Start temporary chat",
9302
+ "aria-pressed": isIncognitoActive,
9462
9303
  sx: {
9463
9304
  ...pillButtonStyles,
9464
- bgcolor: theme.palette.info.main + "20",
9465
- color: theme.palette.info.main,
9466
- "&:hover": {
9467
- ...pillButtonStyles["&:hover"],
9468
- bgcolor: theme.palette.info.main + "30"
9305
+ ...isIncognitoActive && {
9306
+ bgcolor: theme.palette.text.primary,
9307
+ color: theme.palette.getContrastText(theme.palette.text.primary),
9308
+ "&:hover": { bgcolor: theme.palette.text.primary }
9469
9309
  }
9470
9310
  },
9471
- "aria-label": `Change voice. Currently using ${selectedVoice ? toTitleCase(selectedVoice.split("-")[1]) : "default"}`,
9472
- children: /* @__PURE__ */ jsx18(RecordVoiceOverIcon, { fontSize: "small" })
9473
- }
9474
- ) }),
9475
- /* @__PURE__ */ jsx18(
9476
- Menu7,
9477
- {
9478
- anchorEl: voiceAnchorEl,
9479
- open: Boolean(voiceAnchorEl),
9480
- onClose: () => setVoiceAnchorEl(null),
9481
- transformOrigin: { horizontal: "right", vertical: "top" },
9482
- anchorOrigin: { horizontal: "right", vertical: "bottom" },
9483
- PaperProps: {
9484
- sx: {
9485
- bgcolor: menuBackground,
9486
- color: menuText,
9487
- fontSize: "0.875rem",
9488
- zIndex: 2e4,
9489
- borderRadius: 2,
9490
- border: `1px solid ${border}`,
9491
- boxShadow: theme.palette.mode === "dark" ? "0 8px 32px rgba(0,0,0,0.5)" : "0 8px 32px rgba(0,0,0,0.2)",
9492
- minWidth: 180,
9493
- "& .MuiMenuItem-root": {
9494
- transition: "all 0.15s ease-in-out",
9495
- borderRadius: "6px",
9496
- margin: "2px 4px",
9497
- minHeight: 40,
9498
- "&:hover": {
9499
- bgcolor: theme.palette.mode === "dark" ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.04)",
9500
- transform: "translateX(2px)"
9501
- },
9502
- "&.Mui-selected": {
9503
- bgcolor: theme.palette.info.main + "20",
9504
- color: theme.palette.info.main,
9505
- "&:hover": {
9506
- bgcolor: theme.palette.info.main + "30"
9507
- }
9508
- }
9509
- }
9510
- }
9511
- },
9512
- children: availableVoices.length > 0 ? availableVoices.map((voice) => /* @__PURE__ */ jsx18(
9513
- MenuItem7,
9514
- {
9515
- selected: voice === selectedVoice,
9516
- onClick: () => {
9517
- handleVoiceChange(voice);
9518
- setVoiceAnchorEl(null);
9519
- },
9520
- children: /* @__PURE__ */ jsxs15(Box15, { sx: { display: "flex", alignItems: "center", gap: 1, width: "100%" }, children: [
9521
- /* @__PURE__ */ jsx18(RecordVoiceOverIcon, { fontSize: "small", sx: { color: theme.palette.text.secondary } }),
9522
- /* @__PURE__ */ jsxs15(Box15, { sx: { flex: 1 }, children: [
9523
- /* @__PURE__ */ jsx18(Typography12, { variant: "body2", children: toTitleCase(voice.split("-")[1]) }),
9524
- /* @__PURE__ */ jsx18(Typography12, { variant: "caption", sx: { color: theme.palette.text.secondary }, children: voice === selectedVoice ? "Currently active" : "Switch to this voice" })
9525
- ] }),
9526
- voice === selectedVoice && /* @__PURE__ */ jsx18(
9527
- Box15,
9528
- {
9529
- sx: {
9530
- width: 8,
9531
- height: 8,
9532
- borderRadius: "50%",
9533
- bgcolor: theme.palette.info.main
9534
- }
9535
- }
9536
- )
9537
- ] })
9538
- },
9539
- voice
9540
- )) : /* @__PURE__ */ jsx18(MenuItem7, { disabled: true, children: /* @__PURE__ */ jsx18(Typography12, { variant: "body2", color: "text.secondary", children: "No voices available" }) })
9311
+ children: /* @__PURE__ */ jsx18(GhostIcon, {})
9541
9312
  }
9542
9313
  )
9543
- ] })
9544
- ]
9314
+ }
9315
+ )
9545
9316
  }
9546
9317
  )
9547
9318
  ]
@@ -10297,7 +10068,7 @@ var useVoiceMode = (config) => {
10297
10068
  };
10298
10069
 
10299
10070
  // src/chat/chat.tsx
10300
- import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
10071
+ import { Fragment as Fragment12, jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
10301
10072
  var ChatContent = () => {
10302
10073
  const packageSettings = usePackageSettingsStore((state) => state.settings);
10303
10074
  const UnderReviewView = packageSettings?.components?.UnderReview ?? UnderReview_default;
@@ -10412,7 +10183,8 @@ var ChatContent = () => {
10412
10183
  const [inputHeight, setInputHeight] = useState18(80);
10413
10184
  const [isSubmitting, setIsSubmitting] = useState18(false);
10414
10185
  const [pendingMessage, setPendingMessage] = useState18(null);
10415
- const { conversations, currentId, _hasHydrated, hydrate } = useConversationStore();
10186
+ const { conversations, currentId, _hasHydrated, hydrate, toggleIncognito } = useConversationStore();
10187
+ const isTemporaryChat = Boolean(conversations.find((c) => c.id === currentId)?.incognito);
10416
10188
  const [isMobile, setIsMobile] = useState18(false);
10417
10189
  const [drawerOpen, setDrawerOpen] = useState18(false);
10418
10190
  const [mobileConversationsOpen, setMobileConversationsOpen] = useState18(false);
@@ -11265,12 +11037,11 @@ var ChatContent = () => {
11265
11037
  width: !isMobile && canvasOpen ? `calc(100vw - ${drawerOpen ? "340px" : "0px"} - ${CANVAS_WIDTH})` : drawerOpen && !isMobile ? "calc(100vw - 340px)" : "100vw",
11266
11038
  zIndex: 0,
11267
11039
  // Claude-style push (mobile only; desktop stays flush): the chat
11268
- // shell slides right and shrinks slightly into a rounded card. The
11269
- // scale insets the card from every screen edge so all four rounded
11270
- // corners stay visible — a full-height 100dvh card had its bottom
11271
- // corners clipped at the device edge in the PWA. Width kept in sync
11040
+ // shell slides right as a full-height rounded card — exactly like
11041
+ // Claude iOS, where the card runs edge-to-edge vertically and the
11042
+ // hairline border keeps the corners legible. Width kept in sync
11272
11043
  // with the drawer in enhanced-mobile-conversations-modal.tsx.
11273
- transform: isMobile && mobileConversationsOpen ? "translateX(min(calc(100vw - 56px), 360px)) scale(0.96)" : "none",
11044
+ transform: isMobile && mobileConversationsOpen ? "translateX(min(calc(100vw - 56px), 360px))" : "none",
11274
11045
  borderRadius: isMobile && mobileConversationsOpen ? "24px" : 0,
11275
11046
  // Hairline border so the rounded card reads even when the backdrop
11276
11047
  // is the same near-black as the shell.
@@ -11293,30 +11064,82 @@ var ChatContent = () => {
11293
11064
  onMobileConversationsOpenChange: setMobileConversationsOpen
11294
11065
  }
11295
11066
  ),
11296
- conversations.find((c) => c.id === currentId)?.incognito && /* @__PURE__ */ jsx22(
11297
- Box19,
11298
- {
11299
- sx: (theme) => ({
11300
- position: "absolute",
11301
- top: `calc(${theme.spacing(8)} + env(safe-area-inset-top, 0px))`,
11302
- left: "50%",
11303
- transform: "translateX(-50%)",
11304
- zIndex: 1200,
11305
- px: 1.5,
11306
- py: 0.5,
11307
- borderRadius: 999,
11308
- fontSize: "0.75rem",
11309
- fontWeight: 600,
11310
- color: theme.palette.text.secondary,
11311
- bgcolor: theme.palette.mode === "dark" ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.06)",
11312
- border: `1px solid ${theme.palette.divider}`,
11313
- backdropFilter: "blur(8px)",
11314
- pointerEvents: "none",
11315
- whiteSpace: "nowrap"
11316
- }),
11317
- children: "Incognito \u2014 this chat won't be saved"
11318
- }
11319
- ),
11067
+ isTemporaryChat && /* @__PURE__ */ jsxs17(Fragment12, { children: [
11068
+ /* @__PURE__ */ jsx22(
11069
+ Box19,
11070
+ {
11071
+ sx: (theme) => ({
11072
+ position: "absolute",
11073
+ inset: 0,
11074
+ border: `2px solid ${theme.palette.mode === "dark" ? "rgba(255,255,255,0.45)" : "rgba(0,0,0,0.4)"}`,
11075
+ borderRadius: "inherit",
11076
+ zIndex: 1400,
11077
+ pointerEvents: "none"
11078
+ })
11079
+ }
11080
+ ),
11081
+ /* @__PURE__ */ jsxs17(
11082
+ Box19,
11083
+ {
11084
+ sx: (theme) => ({
11085
+ position: "absolute",
11086
+ top: `calc(${theme.spacing(8)} + env(safe-area-inset-top, 0px))`,
11087
+ left: "50%",
11088
+ transform: "translateX(-50%)",
11089
+ zIndex: 1401,
11090
+ display: "flex",
11091
+ alignItems: "center",
11092
+ gap: 0.75,
11093
+ pl: 1.5,
11094
+ pr: 0.75,
11095
+ py: 0.4,
11096
+ borderRadius: 999,
11097
+ fontSize: "0.78rem",
11098
+ fontWeight: 600,
11099
+ color: theme.palette.text.primary,
11100
+ bgcolor: theme.palette.mode === "dark" ? "rgba(255,255,255,0.12)" : "rgba(0,0,0,0.08)",
11101
+ border: `1px solid ${theme.palette.divider}`,
11102
+ backdropFilter: "blur(8px)",
11103
+ whiteSpace: "nowrap"
11104
+ }),
11105
+ children: [
11106
+ /* @__PURE__ */ jsx22(Box19, { component: "span", "aria-hidden": true, sx: { fontSize: "0.9rem", lineHeight: 1 }, children: "\u{1F47B}" }),
11107
+ "Temporary chat",
11108
+ /* @__PURE__ */ jsx22(
11109
+ Box19,
11110
+ {
11111
+ component: "button",
11112
+ type: "button",
11113
+ onClick: toggleIncognito,
11114
+ "aria-label": "End temporary chat",
11115
+ sx: (theme) => ({
11116
+ display: "inline-flex",
11117
+ alignItems: "center",
11118
+ justifyContent: "center",
11119
+ width: 20,
11120
+ height: 20,
11121
+ ml: 0.25,
11122
+ p: 0,
11123
+ border: "none",
11124
+ borderRadius: "50%",
11125
+ cursor: "pointer",
11126
+ color: theme.palette.text.secondary,
11127
+ bgcolor: "transparent",
11128
+ font: "inherit",
11129
+ fontSize: "0.85rem",
11130
+ lineHeight: 1,
11131
+ "&:hover": {
11132
+ bgcolor: theme.palette.mode === "dark" ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.1)",
11133
+ color: theme.palette.text.primary
11134
+ }
11135
+ }),
11136
+ children: "\u2715"
11137
+ }
11138
+ )
11139
+ ]
11140
+ }
11141
+ )
11142
+ ] }),
11320
11143
  /* @__PURE__ */ jsx22(
11321
11144
  Box19,
11322
11145
  {
@@ -11544,4 +11367,4 @@ var chat_default = Chat;
11544
11367
  export {
11545
11368
  chat_default
11546
11369
  };
11547
- //# sourceMappingURL=chunk-JXFPCLEY.mjs.map
11370
+ //# sourceMappingURL=chunk-LQJ6OD7F.mjs.map