@burtson-labs/bandit-engine 2.0.127 → 2.0.129

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-2XYHFUT2.mjs → chat-TO26ORKD.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-RRSACJI2.mjs → chunk-3LOS2EAN.mjs} +135 -448
  6. package/dist/chunk-3LOS2EAN.mjs.map +1 -0
  7. package/dist/{chunk-OLKDPUWL.mjs → chunk-BQW7DSJ6.mjs} +2 -2
  8. package/dist/{chunk-574ILQTT.mjs → chunk-FWFDOSRM.mjs} +2 -2
  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-7NBLIL76.mjs → chunk-VXGJ4XH6.mjs} +23 -6
  14. package/dist/chunk-VXGJ4XH6.mjs.map +1 -0
  15. package/dist/index.js +148 -442
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +7 -7
  18. package/dist/management/management.js +148 -442
  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-7NBLIL76.mjs.map +0 -1
  26. package/dist/chunk-RRSACJI2.mjs.map +0 -1
  27. /package/dist/{chat-2XYHFUT2.mjs.map → chat-TO26ORKD.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
@@ -7655,7 +7655,7 @@ var init_conversationStore = __esm({
7655
7655
  const now = /* @__PURE__ */ new Date();
7656
7656
  const newConv = normalizeConversation({
7657
7657
  id: (0, import_uuid2.v4)(),
7658
- name: "Incognito chat",
7658
+ name: "Temporary chat",
7659
7659
  history: [],
7660
7660
  model: selectedModel,
7661
7661
  createdAt: now,
@@ -20708,7 +20708,7 @@ var init_chat_messages = __esm({
20708
20708
  StreamingMarkdown_default,
20709
20709
  {
20710
20710
  content: linkifyCitations(stripSourcesForDisplay(content), parseWebSources(content)),
20711
- isStreaming: isStreaming && isLast,
20711
+ isStreaming: isStreaming && isLast && !workingMatch,
20712
20712
  sources: sourceSummaries
20713
20713
  }
20714
20714
  ),
@@ -21817,7 +21817,7 @@ ${sanitize(
21817
21817
  fullWidth: true,
21818
21818
  multiline: true,
21819
21819
  maxRows: compactMobile ? 6 : 12,
21820
- placeholder: isIncognito ? "Incognito chat \u2014 not saved" : "What's on your mind?",
21820
+ placeholder: isIncognito ? "Temporary chat \u2014 not saved" : "What's on your mind?",
21821
21821
  value: inputValue,
21822
21822
  onChange: (e) => setInputValue(e.target.value),
21823
21823
  onKeyDown: handleKeyPress,
@@ -21941,7 +21941,7 @@ ${sanitize(
21941
21941
  fullWidth: true,
21942
21942
  multiline: true,
21943
21943
  maxRows: 6,
21944
- placeholder: isIncognito ? "Incognito chat \u2014 not saved" : "What's on your mind?",
21944
+ placeholder: isIncognito ? "Temporary chat \u2014 not saved" : "What's on your mind?",
21945
21945
  value: inputValue,
21946
21946
  onChange: (e) => setInputValue(e.target.value),
21947
21947
  onKeyDown: handleKeyPress,
@@ -21959,26 +21959,29 @@ ${sanitize(
21959
21959
  sx: { flex: 1, alignSelf: "center", mx: 0.5 }
21960
21960
  }
21961
21961
  ),
21962
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_material39.Box, { sx: { display: "flex", alignItems: "center", gap: isMobile ? 0.6 : 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_material39.Tooltip, { title: isStreaming ? "Stop response" : "Send message", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
21963
- import_material39.IconButton,
21964
- {
21965
- onClick: isStreaming ? onStop || (() => {
21966
- }) : handleSubmit,
21967
- disabled: (isStreaming ? false : isSubmitting) || !isStreaming && !inputValue.trim() && pastedImages.length === 0 && fileInputs.length === 0,
21968
- sx: {
21969
- bgcolor: sendButtonBackground,
21970
- color: sendButtonColor,
21971
- borderRadius: "50%",
21972
- width: sendIconSize,
21973
- height: sendIconSize,
21974
- boxShadow: sendButtonShadow,
21975
- transition: "background-color 0.2s ease, box-shadow 0.2s ease",
21976
- "&:hover": { bgcolor: sendButtonHover },
21977
- "&.Mui-disabled": { opacity: 0.5 }
21978
- },
21979
- children: isStreaming ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CloseIcon, { fontSize: "small" }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ArrowUpwardIcon, { fontSize: "small" })
21980
- }
21981
- ) }) }) })
21962
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_material39.Box, { sx: { display: "flex", alignItems: "center", gap: isMobile ? 0.6 : 1 }, children: [
21963
+ !isMobile && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(engine_picker_default, {}),
21964
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_material39.Tooltip, { title: isStreaming ? "Stop response" : "Send message", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
21965
+ import_material39.IconButton,
21966
+ {
21967
+ onClick: isStreaming ? onStop || (() => {
21968
+ }) : handleSubmit,
21969
+ disabled: (isStreaming ? false : isSubmitting) || !isStreaming && !inputValue.trim() && pastedImages.length === 0 && fileInputs.length === 0,
21970
+ sx: {
21971
+ bgcolor: sendButtonBackground,
21972
+ color: sendButtonColor,
21973
+ borderRadius: "50%",
21974
+ width: sendIconSize,
21975
+ height: sendIconSize,
21976
+ boxShadow: sendButtonShadow,
21977
+ transition: "background-color 0.2s ease, box-shadow 0.2s ease",
21978
+ "&:hover": { bgcolor: sendButtonHover },
21979
+ "&.Mui-disabled": { opacity: 0.5 }
21980
+ },
21981
+ children: isStreaming ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CloseIcon, { fontSize: "small" }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ArrowUpwardIcon, { fontSize: "small" })
21982
+ }
21983
+ ) }) })
21984
+ ] })
21982
21985
  ]
21983
21986
  }
21984
21987
  ),
@@ -22025,7 +22028,7 @@ ${sanitize(
22025
22028
  ]
22026
22029
  }
22027
22030
  ),
22028
- !isMobile && /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
22031
+ (!isMobile || isIncognito) && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
22029
22032
  import_material39.Typography,
22030
22033
  {
22031
22034
  variant: "caption",
@@ -22037,10 +22040,7 @@ ${sanitize(
22037
22040
  textAlign: "center",
22038
22041
  pointerEvents: "none"
22039
22042
  },
22040
- children: [
22041
- brandingText || "BanditAI",
22042
- " may be wrong - double-check important info."
22043
- ]
22043
+ children: isIncognito ? "Temporary chats aren't saved to history, synced, or added to memory." : `${brandingText || "BanditAI"} may be wrong - double-check important info.`
22044
22044
  }
22045
22045
  )
22046
22046
  ]
@@ -28958,7 +28958,6 @@ var init_chat_app_bar = __esm({
28958
28958
  import_material49 = require("@mui/material");
28959
28959
  import_react_router_dom3 = require("react-router-dom");
28960
28960
  init_lucide_icons();
28961
- init_util();
28962
28961
  init_conversation_drawer();
28963
28962
  init_enhanced_mobile_conversations_modal();
28964
28963
  init_conversationStore();
@@ -29180,13 +29179,13 @@ var init_chat_app_bar = __esm({
29180
29179
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29181
29180
  import_material49.Tooltip,
29182
29181
  {
29183
- title: isIncognitoActive ? "End incognito chat" : "Start incognito chat \u2014 not saved",
29182
+ title: isIncognitoActive ? "End temporary chat" : "Temporary chat \u2014 not saved anywhere",
29184
29183
  arrow: true,
29185
29184
  children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29186
29185
  import_material49.IconButton,
29187
29186
  {
29188
29187
  onClick: toggleIncognito,
29189
- "aria-label": isIncognitoActive ? "End incognito chat" : "Start incognito chat",
29188
+ "aria-label": isIncognitoActive ? "End temporary chat" : "Start temporary chat",
29190
29189
  "aria-pressed": isIncognitoActive,
29191
29190
  sx: {
29192
29191
  width: 44,
@@ -29285,35 +29284,11 @@ var init_chat_app_bar = __esm({
29285
29284
  "aria-label": "Create new conversation",
29286
29285
  children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(AddIcon, {})
29287
29286
  }
29288
- ) }),
29289
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29290
- import_material49.Tooltip,
29291
- {
29292
- title: isIncognitoActive ? "End incognito chat" : "Start incognito chat \u2014 not saved",
29293
- arrow: true,
29294
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29295
- import_material49.IconButton,
29296
- {
29297
- onClick: toggleIncognito,
29298
- "aria-label": isIncognitoActive ? "End incognito chat" : "Start incognito chat",
29299
- "aria-pressed": isIncognitoActive,
29300
- sx: {
29301
- ...pillButtonStyles,
29302
- ...isIncognitoActive && {
29303
- bgcolor: theme.palette.text.primary,
29304
- color: theme.palette.getContrastText(theme.palette.text.primary),
29305
- "&:hover": { bgcolor: theme.palette.text.primary }
29306
- }
29307
- },
29308
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(GhostIcon, {})
29309
- }
29310
- )
29311
- }
29312
- )
29287
+ ) })
29313
29288
  ]
29314
29289
  }
29315
29290
  ),
29316
- !isMobile && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
29291
+ !isMobile && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29317
29292
  import_material49.Box,
29318
29293
  {
29319
29294
  sx: {
@@ -29333,368 +29308,30 @@ var init_chat_app_bar = __esm({
29333
29308
  boxShadow: theme.palette.mode === "dark" ? "0 6px 20px rgba(0,0,0,0.4)" : "0 6px 20px rgba(0,0,0,0.15)"
29334
29309
  }
29335
29310
  },
29336
- children: [
29337
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Tooltip, { title: `Current AI: ${selectedModel.replace("Bandit-", "")}`, arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29338
- import_material49.IconButton,
29339
- {
29340
- onClick: (e) => setModelAnchorEl(e.currentTarget),
29341
- sx: {
29342
- ...pillButtonStyles,
29343
- "&:hover": {
29344
- ...pillButtonStyles["&:hover"],
29345
- "& .MuiAvatar-root": {
29346
- transform: "scale(1.1)",
29347
- filter: "brightness(2) saturate(1.2)"
29348
- }
29349
- }
29350
- },
29351
- "aria-label": `Change AI personality. Currently using ${selectedModel}`,
29352
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29353
- import_material48.Avatar,
29354
- {
29355
- src: currentAvatar,
29356
- alt: selectedModel,
29357
- sx: {
29358
- width: "36px",
29359
- height: "36px",
29360
- filter: "brightness(1.7)",
29361
- transition: "all 0.2s ease-in-out",
29362
- border: `2px solid ${theme.palette.primary.main}20`
29363
- },
29364
- className: "MuiAvatar-root"
29365
- }
29366
- )
29367
- }
29368
- ) }),
29369
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Tooltip, { title: `Engine \xB7 ${engineDisplay}`, arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29370
- import_material49.IconButton,
29371
- {
29372
- onClick: (e) => setEngineAnchorEl(e.currentTarget),
29373
- sx: pillButtonStyles,
29374
- "aria-label": `Change base model (engine). Currently ${engineDisplay}`,
29375
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(AutoAwesomeIcon, { fontSize: "small" })
29376
- }
29377
- ) }),
29378
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
29379
- import_material49.Menu,
29380
- {
29381
- anchorEl: engineAnchorEl,
29382
- open: Boolean(engineAnchorEl),
29383
- onClose: () => setEngineAnchorEl(null),
29384
- transformOrigin: { horizontal: "right", vertical: "top" },
29385
- anchorOrigin: { horizontal: "right", vertical: "bottom" },
29386
- children: [
29387
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Typography, { variant: "overline", sx: { px: 2, color: theme.palette.text.secondary }, children: "Engine \xB7 base model" }),
29388
- engines.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.MenuItem, { disabled: true, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Typography, { variant: "body2", children: "No engines available" }) }),
29389
- engines.map((engine) => {
29390
- const badges = [
29391
- engine.vision && "vision",
29392
- engine.tools && "tools",
29393
- engine.thinking && "thinking",
29394
- engine.cloud && "cloud"
29395
- ].filter(Boolean);
29396
- const isGated = engine.cloud && !frontierEligible;
29397
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
29398
- import_material49.MenuItem,
29399
- {
29400
- selected: engine.id === resolvedEngineId,
29401
- disabled: !engine.available || isGated,
29402
- onClick: () => {
29403
- if (isGated) return;
29404
- useEngineStore.getState().setSelectedEngine(engine.id);
29405
- setEngineAnchorEl(null);
29406
- },
29407
- sx: {
29408
- display: "flex",
29409
- flexDirection: "column",
29410
- alignItems: "flex-start",
29411
- gap: 0.5,
29412
- py: 1,
29413
- px: 2,
29414
- maxWidth: 360,
29415
- whiteSpace: "normal",
29416
- // Keep gated rows readable (MUI disabled dims to ~38%) so the
29417
- // upsell stays legible.
29418
- ...isGated ? { opacity: 1, "&.Mui-disabled": { opacity: 1 } } : {}
29419
- },
29420
- children: [
29421
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_material49.Box, { sx: { display: "flex", alignItems: "center", gap: 1, width: "100%" }, children: [
29422
- isGated && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29423
- LockIcon,
29424
- {
29425
- fontSize: "small",
29426
- sx: { fontSize: "0.95rem", color: theme.palette.text.secondary }
29427
- }
29428
- ),
29429
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29430
- import_material49.Typography,
29431
- {
29432
- variant: "body2",
29433
- sx: {
29434
- fontWeight: 600,
29435
- flex: 1,
29436
- color: isGated ? theme.palette.text.secondary : void 0
29437
- },
29438
- children: cleanEngineName(engine.displayName)
29439
- }
29440
- ),
29441
- engine.id === resolvedEngineId && !isGated && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Box, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: theme.palette.primary.main } })
29442
- ] }),
29443
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Typography, { 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" }),
29444
- isGated && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29445
- import_material49.Button,
29446
- {
29447
- size: "small",
29448
- variant: "text",
29449
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(LockIcon, { sx: { fontSize: "0.85rem" } }),
29450
- onClick: (e) => {
29451
- e.stopPropagation();
29452
- setEngineAnchorEl(null);
29453
- safeNavigate(plansPath);
29454
- },
29455
- sx: {
29456
- mt: 0.25,
29457
- px: 0.75,
29458
- py: 0.1,
29459
- minWidth: 0,
29460
- textTransform: "none",
29461
- fontSize: "0.7rem",
29462
- fontWeight: 600,
29463
- color: theme.palette.primary.main,
29464
- // Re-enable pointer events the disabled MenuItem strips.
29465
- pointerEvents: "auto"
29466
- },
29467
- children: "Upgrade to unlock"
29468
- }
29469
- ),
29470
- badges.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Box, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap", mt: 0.25 }, children: badges.map((b) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29471
- import_material49.Box,
29472
- {
29473
- sx: {
29474
- fontSize: "0.65rem",
29475
- px: 0.75,
29476
- py: 0.1,
29477
- borderRadius: 1,
29478
- bgcolor: theme.palette.primary.main + "22",
29479
- color: theme.palette.primary.main
29480
- },
29481
- children: b
29482
- },
29483
- b
29484
- )) })
29485
- ]
29486
- },
29487
- engine.id
29488
- );
29489
- })
29490
- ]
29491
- }
29492
- ),
29493
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29494
- import_material49.Menu,
29495
- {
29496
- anchorEl: modelAnchorEl,
29497
- open: Boolean(modelAnchorEl),
29498
- onClose: () => setModelAnchorEl(null),
29499
- transformOrigin: { horizontal: "right", vertical: "top" },
29500
- anchorOrigin: { horizontal: "right", vertical: "bottom" },
29501
- PaperProps: {
29502
- sx: {
29503
- bgcolor: menuBackground,
29504
- color: menuText,
29505
- fontSize: "0.875rem",
29506
- zIndex: 2e4,
29507
- borderRadius: 2,
29508
- border: `1px solid ${border}`,
29509
- boxShadow: theme.palette.mode === "dark" ? "0 8px 32px rgba(0,0,0,0.5)" : "0 8px 32px rgba(0,0,0,0.2)",
29510
- minWidth: 200,
29511
- "& .MuiMenuItem-root": {
29512
- transition: "all 0.15s ease-in-out",
29513
- borderRadius: "6px",
29514
- margin: "2px 4px",
29515
- "&:hover": {
29516
- bgcolor: theme.palette.mode === "dark" ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.04)",
29517
- transform: "translateX(2px)"
29518
- },
29519
- "&.Mui-selected": {
29520
- bgcolor: theme.palette.primary.main + "20",
29521
- color: theme.palette.primary.main,
29522
- "&:hover": {
29523
- bgcolor: theme.palette.primary.main + "30"
29524
- }
29525
- }
29526
- }
29527
- }
29528
- },
29529
- children: availableModels.map((model) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
29530
- import_material49.MenuItem,
29531
- {
29532
- selected: model.name === selectedModel,
29533
- onClick: () => {
29534
- if (!currentConversation?.history.length || currentConversation?.history.length === 0) {
29535
- handleModelChange(model.name);
29536
- useModelStore.getState().setSelectedModel(model.name);
29537
- (async () => {
29538
- try {
29539
- const storeConfigs6 = [{ name: "config", keyPath: "id" }];
29540
- const current = await indexedDBService_default.get(
29541
- "banditConfig",
29542
- 1,
29543
- "config",
29544
- "main",
29545
- storeConfigs6
29546
- );
29547
- const updated = {
29548
- ...current ?? {},
29549
- id: "main",
29550
- model: {
29551
- ...current?.model || {},
29552
- name: model.name,
29553
- selectedModel: model.name
29554
- }
29555
- };
29556
- await indexedDBService_default.put("banditConfig", 1, "config", updated, storeConfigs6);
29557
- } catch (err) {
29558
- debugLogger.error("Failed to persist selectedModel to IndexedDB", { error: err });
29559
- }
29560
- })();
29561
- setModelAnchorEl(null);
29562
- return;
29563
- }
29564
- setPendingModel(model.name);
29565
- setConfirmModelChangeOpen(true);
29566
- setModelAnchorEl(null);
29567
- },
29568
- sx: {
29569
- display: "flex",
29570
- alignItems: "center",
29571
- gap: 1.5,
29572
- minHeight: 48,
29573
- px: 2
29574
- },
29575
- children: [
29576
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29577
- import_material48.Avatar,
29578
- {
29579
- src: model.avatarBase64 || modelAvatars3[model.name] || banditHead4,
29580
- alt: model.name,
29581
- sx: {
29582
- width: 28,
29583
- height: 28,
29584
- filter: "brightness(1.7)",
29585
- transition: "all 0.2s ease-in-out"
29586
- }
29587
- }
29588
- ),
29589
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_material49.Box, { sx: { flex: 1 }, children: [
29590
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Typography, { variant: "body2", sx: { fontWeight: 500 }, children: model.name.replace("Bandit-", "") }),
29591
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Typography, { variant: "caption", sx: { color: theme.palette.text.secondary, display: "block" }, children: model.name === selectedModel ? "Currently active" : "Switch to this AI" })
29592
- ] }),
29593
- model.name === selectedModel && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29594
- import_material49.Box,
29595
- {
29596
- sx: {
29597
- width: 8,
29598
- height: 8,
29599
- borderRadius: "50%",
29600
- bgcolor: theme.palette.primary.main
29601
- }
29602
- }
29603
- )
29604
- ]
29605
- },
29606
- model.name
29607
- ))
29608
- }
29609
- ),
29610
- isTTSAvailable && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
29611
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Tooltip, { title: `Voice: ${selectedVoice ? toTitleCase(selectedVoice.split("-")[1]) : "Default"}`, arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29311
+ children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29312
+ import_material49.Tooltip,
29313
+ {
29314
+ title: isIncognitoActive ? "End temporary chat" : "Temporary chat \u2014 not saved anywhere",
29315
+ arrow: true,
29316
+ children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29612
29317
  import_material49.IconButton,
29613
29318
  {
29614
- onClick: (e) => setVoiceAnchorEl(e.currentTarget),
29319
+ onClick: toggleIncognito,
29320
+ "aria-label": isIncognitoActive ? "End temporary chat" : "Start temporary chat",
29321
+ "aria-pressed": isIncognitoActive,
29615
29322
  sx: {
29616
29323
  ...pillButtonStyles,
29617
- bgcolor: theme.palette.info.main + "20",
29618
- color: theme.palette.info.main,
29619
- "&:hover": {
29620
- ...pillButtonStyles["&:hover"],
29621
- bgcolor: theme.palette.info.main + "30"
29622
- }
29623
- },
29624
- "aria-label": `Change voice. Currently using ${selectedVoice ? toTitleCase(selectedVoice.split("-")[1]) : "default"}`,
29625
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(RecordVoiceOverIcon, { fontSize: "small" })
29626
- }
29627
- ) }),
29628
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29629
- import_material49.Menu,
29630
- {
29631
- anchorEl: voiceAnchorEl,
29632
- open: Boolean(voiceAnchorEl),
29633
- onClose: () => setVoiceAnchorEl(null),
29634
- transformOrigin: { horizontal: "right", vertical: "top" },
29635
- anchorOrigin: { horizontal: "right", vertical: "bottom" },
29636
- PaperProps: {
29637
- sx: {
29638
- bgcolor: menuBackground,
29639
- color: menuText,
29640
- fontSize: "0.875rem",
29641
- zIndex: 2e4,
29642
- borderRadius: 2,
29643
- border: `1px solid ${border}`,
29644
- boxShadow: theme.palette.mode === "dark" ? "0 8px 32px rgba(0,0,0,0.5)" : "0 8px 32px rgba(0,0,0,0.2)",
29645
- minWidth: 180,
29646
- "& .MuiMenuItem-root": {
29647
- transition: "all 0.15s ease-in-out",
29648
- borderRadius: "6px",
29649
- margin: "2px 4px",
29650
- minHeight: 40,
29651
- "&:hover": {
29652
- bgcolor: theme.palette.mode === "dark" ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.04)",
29653
- transform: "translateX(2px)"
29654
- },
29655
- "&.Mui-selected": {
29656
- bgcolor: theme.palette.info.main + "20",
29657
- color: theme.palette.info.main,
29658
- "&:hover": {
29659
- bgcolor: theme.palette.info.main + "30"
29660
- }
29661
- }
29662
- }
29324
+ ...isIncognitoActive && {
29325
+ bgcolor: theme.palette.text.primary,
29326
+ color: theme.palette.getContrastText(theme.palette.text.primary),
29327
+ "&:hover": { bgcolor: theme.palette.text.primary }
29663
29328
  }
29664
29329
  },
29665
- children: availableVoices.length > 0 ? availableVoices.map((voice) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29666
- import_material49.MenuItem,
29667
- {
29668
- selected: voice === selectedVoice,
29669
- onClick: () => {
29670
- handleVoiceChange(voice);
29671
- setVoiceAnchorEl(null);
29672
- },
29673
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_material49.Box, { sx: { display: "flex", alignItems: "center", gap: 1, width: "100%" }, children: [
29674
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(RecordVoiceOverIcon, { fontSize: "small", sx: { color: theme.palette.text.secondary } }),
29675
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_material49.Box, { sx: { flex: 1 }, children: [
29676
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Typography, { variant: "body2", children: toTitleCase(voice.split("-")[1]) }),
29677
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Typography, { variant: "caption", sx: { color: theme.palette.text.secondary }, children: voice === selectedVoice ? "Currently active" : "Switch to this voice" })
29678
- ] }),
29679
- voice === selectedVoice && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
29680
- import_material49.Box,
29681
- {
29682
- sx: {
29683
- width: 8,
29684
- height: 8,
29685
- borderRadius: "50%",
29686
- bgcolor: theme.palette.info.main
29687
- }
29688
- }
29689
- )
29690
- ] })
29691
- },
29692
- voice
29693
- )) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.MenuItem, { disabled: true, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_material49.Typography, { variant: "body2", color: "text.secondary", children: "No voices available" }) })
29330
+ children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(GhostIcon, {})
29694
29331
  }
29695
29332
  )
29696
- ] })
29697
- ]
29333
+ }
29334
+ )
29698
29335
  }
29699
29336
  )
29700
29337
  ]
@@ -30663,7 +30300,8 @@ var init_chat2 = __esm({
30663
30300
  const [inputHeight, setInputHeight] = (0, import_react62.useState)(80);
30664
30301
  const [isSubmitting, setIsSubmitting] = (0, import_react62.useState)(false);
30665
30302
  const [pendingMessage, setPendingMessage] = (0, import_react62.useState)(null);
30666
- const { conversations, currentId, _hasHydrated, hydrate } = useConversationStore();
30303
+ const { conversations, currentId, _hasHydrated, hydrate, toggleIncognito } = useConversationStore();
30304
+ const isTemporaryChat = Boolean(conversations.find((c) => c.id === currentId)?.incognito);
30667
30305
  const [isMobile, setIsMobile] = (0, import_react62.useState)(false);
30668
30306
  const [drawerOpen, setDrawerOpen] = (0, import_react62.useState)(false);
30669
30307
  const [mobileConversationsOpen, setMobileConversationsOpen] = (0, import_react62.useState)(false);
@@ -31516,12 +31154,11 @@ var init_chat2 = __esm({
31516
31154
  width: !isMobile && canvasOpen ? `calc(100vw - ${drawerOpen ? "340px" : "0px"} - ${CANVAS_WIDTH})` : drawerOpen && !isMobile ? "calc(100vw - 340px)" : "100vw",
31517
31155
  zIndex: 0,
31518
31156
  // Claude-style push (mobile only; desktop stays flush): the chat
31519
- // shell slides right and shrinks slightly into a rounded card. The
31520
- // scale insets the card from every screen edge so all four rounded
31521
- // corners stay visible — a full-height 100dvh card had its bottom
31522
- // corners clipped at the device edge in the PWA. Width kept in sync
31157
+ // shell slides right as a full-height rounded card — exactly like
31158
+ // Claude iOS, where the card runs edge-to-edge vertically and the
31159
+ // hairline border keeps the corners legible. Width kept in sync
31523
31160
  // with the drawer in enhanced-mobile-conversations-modal.tsx.
31524
- transform: isMobile && mobileConversationsOpen ? "translateX(min(calc(100vw - 56px), 360px)) scale(0.96)" : "none",
31161
+ transform: isMobile && mobileConversationsOpen ? "translateX(min(calc(100vw - 56px), 360px))" : "none",
31525
31162
  borderRadius: isMobile && mobileConversationsOpen ? "24px" : 0,
31526
31163
  // Hairline border so the rounded card reads even when the backdrop
31527
31164
  // is the same near-black as the shell.
@@ -31544,30 +31181,82 @@ var init_chat2 = __esm({
31544
31181
  onMobileConversationsOpenChange: setMobileConversationsOpen
31545
31182
  }
31546
31183
  ),
31547
- conversations.find((c) => c.id === currentId)?.incognito && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31548
- import_material53.Box,
31549
- {
31550
- sx: (theme) => ({
31551
- position: "absolute",
31552
- top: `calc(${theme.spacing(8)} + env(safe-area-inset-top, 0px))`,
31553
- left: "50%",
31554
- transform: "translateX(-50%)",
31555
- zIndex: 1200,
31556
- px: 1.5,
31557
- py: 0.5,
31558
- borderRadius: 999,
31559
- fontSize: "0.75rem",
31560
- fontWeight: 600,
31561
- color: theme.palette.text.secondary,
31562
- bgcolor: theme.palette.mode === "dark" ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.06)",
31563
- border: `1px solid ${theme.palette.divider}`,
31564
- backdropFilter: "blur(8px)",
31565
- pointerEvents: "none",
31566
- whiteSpace: "nowrap"
31567
- }),
31568
- children: "Incognito \u2014 this chat won't be saved"
31569
- }
31570
- ),
31184
+ isTemporaryChat && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
31185
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31186
+ import_material53.Box,
31187
+ {
31188
+ sx: (theme) => ({
31189
+ position: "absolute",
31190
+ inset: 0,
31191
+ border: `2px solid ${theme.palette.mode === "dark" ? "rgba(255,255,255,0.45)" : "rgba(0,0,0,0.4)"}`,
31192
+ borderRadius: "inherit",
31193
+ zIndex: 1400,
31194
+ pointerEvents: "none"
31195
+ })
31196
+ }
31197
+ ),
31198
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
31199
+ import_material53.Box,
31200
+ {
31201
+ sx: (theme) => ({
31202
+ position: "absolute",
31203
+ top: `calc(${theme.spacing(8)} + env(safe-area-inset-top, 0px))`,
31204
+ left: "50%",
31205
+ transform: "translateX(-50%)",
31206
+ zIndex: 1401,
31207
+ display: "flex",
31208
+ alignItems: "center",
31209
+ gap: 0.75,
31210
+ pl: 1.5,
31211
+ pr: 0.75,
31212
+ py: 0.4,
31213
+ borderRadius: 999,
31214
+ fontSize: "0.78rem",
31215
+ fontWeight: 600,
31216
+ color: theme.palette.text.primary,
31217
+ bgcolor: theme.palette.mode === "dark" ? "rgba(255,255,255,0.12)" : "rgba(0,0,0,0.08)",
31218
+ border: `1px solid ${theme.palette.divider}`,
31219
+ backdropFilter: "blur(8px)",
31220
+ whiteSpace: "nowrap"
31221
+ }),
31222
+ 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}" }),
31224
+ "Temporary chat",
31225
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31226
+ import_material53.Box,
31227
+ {
31228
+ component: "button",
31229
+ type: "button",
31230
+ onClick: toggleIncognito,
31231
+ "aria-label": "End temporary chat",
31232
+ sx: (theme) => ({
31233
+ display: "inline-flex",
31234
+ alignItems: "center",
31235
+ justifyContent: "center",
31236
+ width: 20,
31237
+ height: 20,
31238
+ ml: 0.25,
31239
+ p: 0,
31240
+ border: "none",
31241
+ borderRadius: "50%",
31242
+ cursor: "pointer",
31243
+ color: theme.palette.text.secondary,
31244
+ bgcolor: "transparent",
31245
+ font: "inherit",
31246
+ fontSize: "0.85rem",
31247
+ lineHeight: 1,
31248
+ "&:hover": {
31249
+ bgcolor: theme.palette.mode === "dark" ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.1)",
31250
+ color: theme.palette.text.primary
31251
+ }
31252
+ }),
31253
+ children: "\u2715"
31254
+ }
31255
+ )
31256
+ ]
31257
+ }
31258
+ )
31259
+ ] }),
31571
31260
  /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
31572
31261
  import_material53.Box,
31573
31262
  {
@@ -45342,6 +45031,23 @@ var Management = () => {
45342
45031
  boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
45343
45032
  },
45344
45033
  children: [
45034
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45035
+ import_material54.Button,
45036
+ {
45037
+ onClick: () => navigate("/chat"),
45038
+ onMouseEnter: preloadChatPage,
45039
+ "aria-label": "Back to chat",
45040
+ sx: {
45041
+ minWidth: 48,
45042
+ minHeight: 48,
45043
+ p: 1.5,
45044
+ borderRadius: 2,
45045
+ color: "primary.main",
45046
+ bgcolor: (theme2) => theme2.palette.mode === "dark" ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.04)"
45047
+ },
45048
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ChevronLeftIcon, { sx: { fontSize: 22 } })
45049
+ }
45050
+ ),
45345
45051
  /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
45346
45052
  import_material54.Button,
45347
45053
  {