@burtson-labs/bandit-engine 2.0.149 → 2.0.151

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 (42) hide show
  1. package/dist/{aiProviderStore-FTD277QP.mjs → aiProviderStore-ZQ5VVVKQ.mjs} +2 -2
  2. package/dist/chat-3HV3GM5P.mjs +16 -0
  3. package/dist/chat-provider.js +5 -2
  4. package/dist/chat-provider.js.map +1 -1
  5. package/dist/chat-provider.mjs +5 -5
  6. package/dist/{chunk-P5IJLX6I.mjs → chunk-6STVJJSG.mjs} +4 -2
  7. package/dist/chunk-6STVJJSG.mjs.map +1 -0
  8. package/dist/{chunk-K2JGFKEB.mjs → chunk-CVFFNX7H.mjs} +2 -2
  9. package/dist/{chunk-JQSZNGII.mjs → chunk-DSYE5AHW.mjs} +9 -9
  10. package/dist/{chunk-43MLINPL.mjs → chunk-GWQRTUKF.mjs} +6 -3
  11. package/dist/chunk-GWQRTUKF.mjs.map +1 -0
  12. package/dist/{chunk-PU74BI6Y.mjs → chunk-QLATFSSO.mjs} +5 -5
  13. package/dist/{chunk-F7JXIW6T.mjs → chunk-RRCCSN3N.mjs} +2 -2
  14. package/dist/{chunk-F735W34E.mjs → chunk-TYRYAAP2.mjs} +38 -3
  15. package/dist/chunk-TYRYAAP2.mjs.map +1 -0
  16. package/dist/{chunk-K6IV4LYZ.mjs → chunk-U33KBX3Y.mjs} +4 -4
  17. package/dist/{chunk-NLBZZP3B.mjs → chunk-VLUXQE24.mjs} +3 -3
  18. package/dist/{chunk-ANX33XAO.mjs → chunk-ZRJYLJKZ.mjs} +65 -22
  19. package/dist/chunk-ZRJYLJKZ.mjs.map +1 -0
  20. package/dist/index.js +142 -52
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.mjs +10 -10
  23. package/dist/management/management.js +136 -46
  24. package/dist/management/management.js.map +1 -1
  25. package/dist/management/management.mjs +8 -8
  26. package/dist/modals/chat-modal/chat-modal.js +40 -2
  27. package/dist/modals/chat-modal/chat-modal.js.map +1 -1
  28. package/dist/modals/chat-modal/chat-modal.mjs +4 -4
  29. package/package.json +1 -1
  30. package/dist/chat-Z4SQGSMN.mjs +0 -16
  31. package/dist/chunk-43MLINPL.mjs.map +0 -1
  32. package/dist/chunk-ANX33XAO.mjs.map +0 -1
  33. package/dist/chunk-F735W34E.mjs.map +0 -1
  34. package/dist/chunk-P5IJLX6I.mjs.map +0 -1
  35. /package/dist/{aiProviderStore-FTD277QP.mjs.map → aiProviderStore-ZQ5VVVKQ.mjs.map} +0 -0
  36. /package/dist/{chat-Z4SQGSMN.mjs.map → chat-3HV3GM5P.mjs.map} +0 -0
  37. /package/dist/{chunk-K2JGFKEB.mjs.map → chunk-CVFFNX7H.mjs.map} +0 -0
  38. /package/dist/{chunk-JQSZNGII.mjs.map → chunk-DSYE5AHW.mjs.map} +0 -0
  39. /package/dist/{chunk-PU74BI6Y.mjs.map → chunk-QLATFSSO.mjs.map} +0 -0
  40. /package/dist/{chunk-F7JXIW6T.mjs.map → chunk-RRCCSN3N.mjs.map} +0 -0
  41. /package/dist/{chunk-K6IV4LYZ.mjs.map → chunk-U33KBX3Y.mjs.map} +0 -0
  42. /package/dist/{chunk-NLBZZP3B.mjs.map → chunk-VLUXQE24.mjs.map} +0 -0
package/dist/index.js CHANGED
@@ -232,7 +232,7 @@ function emitAuthTokenChanged(token) {
232
232
  detail: { token }
233
233
  }));
234
234
  }
235
- var TOKEN_KEY2, AUTH_TOKEN_CHANGED_EVENT, AuthenticationService, authenticationService;
235
+ var TOKEN_KEY2, AUTH_TOKEN_CHANGED_EVENT, AuthenticationService, authenticationService2;
236
236
  var init_authenticationService = __esm({
237
237
  "src/services/auth/authenticationService.ts"() {
238
238
  "use strict";
@@ -285,7 +285,7 @@ var init_authenticationService = __esm({
285
285
  }
286
286
  }
287
287
  };
288
- authenticationService = new AuthenticationService();
288
+ authenticationService2 = new AuthenticationService();
289
289
  }
290
290
  });
291
291
 
@@ -2149,7 +2149,7 @@ function buildUrl(path) {
2149
2149
  }
2150
2150
  function buildHeaders() {
2151
2151
  const headers = { "Content-Type": "application/json" };
2152
- const token = authenticationService.getToken();
2152
+ const token = authenticationService2.getToken();
2153
2153
  if (token) {
2154
2154
  headers["Authorization"] = `Bearer ${token}`;
2155
2155
  }
@@ -2297,7 +2297,7 @@ function resolveAuthIdentity(token) {
2297
2297
  if (!token) {
2298
2298
  return null;
2299
2299
  }
2300
- const claims = authenticationService.parseJwtClaims(token);
2300
+ const claims = authenticationService2.parseJwtClaims(token);
2301
2301
  if (claims?.sub) {
2302
2302
  return claims.sub;
2303
2303
  }
@@ -2830,7 +2830,7 @@ var init_conversationSyncStore = __esm({
2830
2830
  async initialize() {
2831
2831
  ensureTrackersInitialized();
2832
2832
  const gatewayUrl = usePackageSettingsStore.getState().settings?.gatewayApiUrl;
2833
- const token = authenticationService.getToken();
2833
+ const token = authenticationService2.getToken();
2834
2834
  const tokenIdentity = resolveAuthIdentity(token);
2835
2835
  const current = get();
2836
2836
  const storedIdentity = getStoredSyncIdentity();
@@ -2956,10 +2956,10 @@ var init_conversationSyncStore = __esm({
2956
2956
  });
2957
2957
  set({
2958
2958
  hasLoadedPreference: true,
2959
- initializedForToken: authenticationService.getToken(),
2960
- initializedForIdentity: resolveAuthIdentity(authenticationService.getToken())
2959
+ initializedForToken: authenticationService2.getToken(),
2960
+ initializedForIdentity: resolveAuthIdentity(authenticationService2.getToken())
2961
2961
  });
2962
- setStoredSyncIdentity(resolveAuthIdentity(authenticationService.getToken()));
2962
+ setStoredSyncIdentity(resolveAuthIdentity(authenticationService2.getToken()));
2963
2963
  if (enabled) {
2964
2964
  set({ hasCompletedInitialUpload: false });
2965
2965
  }
@@ -2999,10 +2999,10 @@ var init_conversationSyncStore = __esm({
2999
2999
  });
3000
3000
  set({
3001
3001
  hasLoadedPreference: true,
3002
- initializedForToken: authenticationService.getToken(),
3003
- initializedForIdentity: resolveAuthIdentity(authenticationService.getToken())
3002
+ initializedForToken: authenticationService2.getToken(),
3003
+ initializedForIdentity: resolveAuthIdentity(authenticationService2.getToken())
3004
3004
  });
3005
- setStoredSyncIdentity(resolveAuthIdentity(authenticationService.getToken()));
3005
+ setStoredSyncIdentity(resolveAuthIdentity(authenticationService2.getToken()));
3006
3006
  if (preference.syncEnabled && preference.isAdvancedVectorFeaturesEnabled) {
3007
3007
  await get().runSync({ force: true });
3008
3008
  }
@@ -3042,7 +3042,7 @@ var init_conversationSyncStore = __esm({
3042
3042
  debugLogger.error("conversationSyncStore: runSync error - missing gateway URL");
3043
3043
  return;
3044
3044
  }
3045
- const token = authenticationService.getToken();
3045
+ const token = authenticationService2.getToken();
3046
3046
  if (!token) {
3047
3047
  set({ status: "error", lastError: "Authentication required to sync conversations." });
3048
3048
  debugLogger.error("conversationSyncStore: runSync error - missing auth token");
@@ -3342,7 +3342,7 @@ var init_mcpServersService = __esm({
3342
3342
  };
3343
3343
  authHeaders = () => {
3344
3344
  const headers = { "Content-Type": "application/json" };
3345
- const token = authenticationService.getToken();
3345
+ const token = authenticationService2.getToken();
3346
3346
  if (token) headers["Authorization"] = `Bearer ${token}`;
3347
3347
  return headers;
3348
3348
  };
@@ -4778,12 +4778,15 @@ var init_gateway_service = __esm({
4778
4778
  return;
4779
4779
  }
4780
4780
  const data = error.response?.data;
4781
- const code = data?.code;
4782
- if (code !== "FORCE_RELOGIN" && code !== "ACCOUNT_LOCKED") {
4781
+ let code = data?.code;
4782
+ if (status === 401 && !code) {
4783
+ code = "TOKEN_EXPIRED";
4784
+ }
4785
+ if (code !== "FORCE_RELOGIN" && code !== "ACCOUNT_LOCKED" && code !== "TOKEN_EXPIRED") {
4783
4786
  return;
4784
4787
  }
4785
4788
  try {
4786
- authenticationService.clearToken();
4789
+ authenticationService2.clearToken();
4787
4790
  } catch {
4788
4791
  }
4789
4792
  if (typeof window !== "undefined" && typeof window.dispatchEvent === "function") {
@@ -11424,6 +11427,46 @@ var init_lucide_icons = __esm({
11424
11427
  }
11425
11428
  });
11426
11429
 
11430
+ // src/utils/openFileLink.ts
11431
+ var FILE_EXT_RE, isStandalonePwa, isFileLink, maybeHandleFileLinkClick;
11432
+ var init_openFileLink = __esm({
11433
+ "src/utils/openFileLink.ts"() {
11434
+ "use strict";
11435
+ init_debugLogger();
11436
+ FILE_EXT_RE = /\.(docx|pptx|xlsx|csv|json|md|txt|html|xml|ya?ml|pdf|zip)(?:[?#]|$)/i;
11437
+ isStandalonePwa = () => typeof window !== "undefined" && (window.matchMedia?.("(display-mode: standalone)").matches || window.navigator.standalone === true);
11438
+ isFileLink = (href) => Boolean(href && FILE_EXT_RE.test(href));
11439
+ maybeHandleFileLinkClick = (event, href) => {
11440
+ if (!href || !isStandalonePwa() || !isFileLink(href)) return;
11441
+ event.preventDefault();
11442
+ void (async () => {
11443
+ try {
11444
+ const res = await fetch(href);
11445
+ if (!res.ok) throw new Error(`fetch ${res.status}`);
11446
+ const blob = await res.blob();
11447
+ const rawName = new URL(href, window.location.href).pathname.split("/").pop() || "download";
11448
+ const name = decodeURIComponent(rawName);
11449
+ const file = new File([blob], name, {
11450
+ type: blob.type || "application/octet-stream"
11451
+ });
11452
+ const nav = navigator;
11453
+ if (nav.canShare?.({ files: [file] }) && nav.share) {
11454
+ await nav.share({ files: [file], title: name });
11455
+ return;
11456
+ }
11457
+ window.location.href = URL.createObjectURL(blob);
11458
+ } catch (error) {
11459
+ debugLogger.warn("openFileLink: share flow failed, falling back", {
11460
+ error: error instanceof Error ? error.message : String(error)
11461
+ });
11462
+ if (error?.name === "AbortError") return;
11463
+ window.open(href, "_blank", "noopener");
11464
+ }
11465
+ })();
11466
+ };
11467
+ }
11468
+ });
11469
+
11427
11470
  // src/components/StreamingMarkdown.tsx
11428
11471
  var import_react10, import_material4, import_react_markdown, import_remark_gfm, import_rehype_raw, import_rehype_sanitize2, import_styles2, import_jsx_runtime6, StreamingMarkdown, arePropsEqual, StreamingMarkdown_default;
11429
11472
  var init_StreamingMarkdown = __esm({
@@ -11439,6 +11482,7 @@ var init_StreamingMarkdown = __esm({
11439
11482
  init_lowlight();
11440
11483
  init_markdownRendering();
11441
11484
  init_lucide_icons();
11485
+ init_openFileLink();
11442
11486
  import_jsx_runtime6 = require("react/jsx-runtime");
11443
11487
  StreamingMarkdown = ({
11444
11488
  content,
@@ -11592,6 +11636,7 @@ ${listMarkdown}`;
11592
11636
  href,
11593
11637
  target: "_blank",
11594
11638
  rel: "noopener noreferrer",
11639
+ onClick: (e) => maybeHandleFileLinkClick(e, href),
11595
11640
  style: {
11596
11641
  color: theme.palette.info?.main ?? theme.palette.primary.main,
11597
11642
  textDecoration: "underline",
@@ -13523,7 +13568,7 @@ var init_voiceService = __esm({
13523
13568
  debugLogger.error("Gateway API URL not configured");
13524
13569
  throw new Error("Gateway API URL not configured");
13525
13570
  }
13526
- const token = authenticationService.getToken();
13571
+ const token = authenticationService2.getToken();
13527
13572
  if (!token) {
13528
13573
  debugLogger.warn("No JWT token available - skipping voice models fetch");
13529
13574
  const emptyModels = {
@@ -13533,7 +13578,7 @@ var init_voiceService = __esm({
13533
13578
  };
13534
13579
  return emptyModels;
13535
13580
  }
13536
- if (authenticationService.isTokenExpired(token)) {
13581
+ if (authenticationService2.isTokenExpired(token)) {
13537
13582
  debugLogger.warn("JWT token is expired - skipping voice models fetch");
13538
13583
  const emptyModels = {
13539
13584
  models: [],
@@ -13622,7 +13667,7 @@ var init_tts_client = __esm({
13622
13667
  init_packageSettingsStore();
13623
13668
  init_debugLogger();
13624
13669
  getOrAppendAuthHeader = (existing = {}) => {
13625
- const token = authenticationService.getToken();
13670
+ const token = authenticationService2.getToken();
13626
13671
  if (token) {
13627
13672
  existing["Authorization"] = `Bearer ${token}`;
13628
13673
  return existing;
@@ -14319,8 +14364,8 @@ var init_ai_response_action_bar = __esm({
14319
14364
  const { preferences } = usePreferencesStore();
14320
14365
  const { settings: packageSettings } = usePackageSettingsStore();
14321
14366
  (0, import_react16.useEffect)(() => {
14322
- const isAuthenticated = authenticationService.isAuthenticated();
14323
- const token = authenticationService.getToken();
14367
+ const isAuthenticated = authenticationService2.isAuthenticated();
14368
+ const token = authenticationService2.getToken();
14324
14369
  if (!initialized || availableVoices.length === 0) {
14325
14370
  if (token && isAuthenticated) {
14326
14371
  debugLogger.debug("AI Action Bar: Voices not initialized or unavailable, attempting to load from API");
@@ -14509,6 +14554,7 @@ var init_ai_response_text_field = __esm({
14509
14554
  init_lowlight();
14510
14555
  init_markdownRendering();
14511
14556
  init_lucide_icons();
14557
+ init_openFileLink();
14512
14558
  init_ai_response_action_bar();
14513
14559
  import_jsx_runtime13 = require("react/jsx-runtime");
14514
14560
  brainIcon = "https://cdn.burtson.ai/images/brain-icon.png";
@@ -14941,6 +14987,7 @@ ${sourcesMarkdownList.join("\n")}`;
14941
14987
  },
14942
14988
  target: "_blank",
14943
14989
  rel: "noopener noreferrer",
14990
+ onClick: (e) => maybeHandleFileLinkClick(e, href),
14944
14991
  children
14945
14992
  }
14946
14993
  );
@@ -15980,7 +16027,7 @@ var init_engineStore = __esm({
15980
16027
  }
15981
16028
  try {
15982
16029
  const headers = { "Content-Type": "application/json" };
15983
- const token = authenticationService.getToken();
16030
+ const token = authenticationService2.getToken();
15984
16031
  if (token) headers["Authorization"] = `Bearer ${token}`;
15985
16032
  const res = await fetch(`${base}/models`, { headers });
15986
16033
  const data = await res.json();
@@ -16298,7 +16345,7 @@ var init_stt_client = __esm({
16298
16345
  filename,
16299
16346
  url: `${gatewayUrl}/stt/transcribe`
16300
16347
  });
16301
- const token = authenticationService.getToken();
16348
+ const token = authenticationService2.getToken();
16302
16349
  const response = await fetch(`${gatewayUrl}/stt/transcribe`, {
16303
16350
  method: "POST",
16304
16351
  headers: {
@@ -19386,7 +19433,7 @@ function syncTelemetry() {
19386
19433
  const settings = usePackageSettingsStore.getState().settings;
19387
19434
  const cfg = resolveTelemetryConfig({
19388
19435
  telemetry: settings?.telemetry,
19389
- banditApiKey: authenticationService.getToken() ?? void 0
19436
+ banditApiKey: authenticationService2.getToken() ?? void 0
19390
19437
  });
19391
19438
  active = cfg ? new TelemetryExporter(cfg) : null;
19392
19439
  } catch {
@@ -20037,7 +20084,7 @@ var init_mcpService = __esm({
20037
20084
  }
20038
20085
  if (tool.mcpServerId) {
20039
20086
  const base2 = settings.gatewayApiUrl.replace(/\/$/, "");
20040
- const token2 = authenticationService.getToken();
20087
+ const token2 = authenticationService2.getToken();
20041
20088
  const controller2 = new AbortController();
20042
20089
  const timeoutId2 = setTimeout(() => controller2.abort(), 3e4);
20043
20090
  try {
@@ -20084,7 +20131,7 @@ var init_mcpService = __esm({
20084
20131
  "Content-Type": "application/json"
20085
20132
  }
20086
20133
  };
20087
- const token = authenticationService.getToken();
20134
+ const token = authenticationService2.getToken();
20088
20135
  if (token) {
20089
20136
  requestOptions.headers = {
20090
20137
  ...requestOptions.headers,
@@ -21082,6 +21129,29 @@ ${protocol}`;
21082
21129
  overrideComponentStatus("Idle");
21083
21130
  setIsSubmitting(false);
21084
21131
  setIsStreaming(false);
21132
+ if (/lifetime validation|token.*(expired|invalid)|unauthorized|\b401\b/i.test(err.message || "")) {
21133
+ const { replaceLastAnswer: replaceLastAnswer2 } = useConversationStore.getState();
21134
+ replaceLastAnswer2(
21135
+ "_Your session ended \u2014 sign back in to continue._",
21136
+ lastPartialRef.current.images,
21137
+ false,
21138
+ lastPartialRef.current.usedDocs,
21139
+ true
21140
+ );
21141
+ setResponse("");
21142
+ setStreamBuffer("");
21143
+ setIsThinking?.(false);
21144
+ setPendingMessage(null);
21145
+ try {
21146
+ authenticationService.clearToken();
21147
+ } catch {
21148
+ }
21149
+ window.dispatchEvent(
21150
+ new CustomEvent("auth:force-relogin", { detail: { code: "TOKEN_EXPIRED" } })
21151
+ );
21152
+ telemetryEndTurn({ error: "auth_expired" });
21153
+ return;
21154
+ }
21085
21155
  const rateLimit = parseRateLimitError(err);
21086
21156
  if (rateLimit) {
21087
21157
  debugLogger.info("Chat hit usage limit (429) \u2014 showing upgrade prompt", {
@@ -22236,7 +22306,7 @@ var init_FeedbackModal = __esm({
22236
22306
  }
22237
22307
  const gatewayService = new GatewayService(
22238
22308
  gatewayUrl,
22239
- () => authenticationService.getToken(),
22309
+ () => authenticationService2.getToken(),
22240
22310
  feedbackEmail || settings?.feedbackEmail
22241
22311
  );
22242
22312
  const feedbackRequest = {
@@ -25465,7 +25535,7 @@ var init_conversation_drawer = __esm({
25465
25535
  title: "Sign out",
25466
25536
  onClick: (event) => {
25467
25537
  event.stopPropagation();
25468
- authenticationService.clearToken();
25538
+ authenticationService2.clearToken();
25469
25539
  window.location.href = "/login";
25470
25540
  },
25471
25541
  sx: {
@@ -26581,7 +26651,7 @@ var init_enhanced_mobile_conversations_modal = __esm({
26581
26651
  title: "Sign out",
26582
26652
  onClick: (event) => {
26583
26653
  event.stopPropagation();
26584
- authenticationService.clearToken();
26654
+ authenticationService2.clearToken();
26585
26655
  window.location.href = "/login";
26586
26656
  },
26587
26657
  sx: {
@@ -29920,7 +29990,7 @@ var init_UnderReview = __esm({
29920
29990
  const theme = (0, import_material30.useTheme)();
29921
29991
  const navigate = (0, import_react_router_dom3.useNavigate)();
29922
29992
  const handleResetSession = () => {
29923
- authenticationService.clearToken();
29993
+ authenticationService2.clearToken();
29924
29994
  navigate("/login");
29925
29995
  };
29926
29996
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
@@ -30623,8 +30693,8 @@ var init_chat2 = __esm({
30623
30693
  const notificationService2 = useNotificationService();
30624
30694
  const [selectedTheme, setSelectedTheme] = (0, import_react41.useState)(null);
30625
30695
  const [themeLoading, setThemeLoading] = (0, import_react41.useState)(true);
30626
- const token = authenticationService.getToken();
30627
- const claims = token ? authenticationService.parseJwtClaims(token) : null;
30696
+ const token = authenticationService2.getToken();
30697
+ const claims = token ? authenticationService2.parseJwtClaims(token) : null;
30628
30698
  const baseTheme = themeMap_default[selectedTheme ?? "bandit-dark"] || banditDarkTheme;
30629
30699
  const banditTheme = (0, import_react41.useMemo)(() => {
30630
30700
  return (0, import_styles33.createTheme)(baseTheme, {
@@ -30697,7 +30767,7 @@ var init_chat2 = __esm({
30697
30767
  } = useTTS();
30698
30768
  (0, import_react41.useEffect)(() => {
30699
30769
  const timer = setTimeout(() => {
30700
- const isAuthenticated = authenticationService.isAuthenticated();
30770
+ const isAuthenticated = authenticationService2.isAuthenticated();
30701
30771
  if (!initialized || availableVoices.length === 0) {
30702
30772
  if (token && isAuthenticated) {
30703
30773
  debugLogger.debug("Chat: Voices not initialized or unavailable, attempting to load from API");
@@ -30710,7 +30780,7 @@ var init_chat2 = __esm({
30710
30780
  return () => clearTimeout(timer);
30711
30781
  }, [initialized, availableVoices.length, loadVoicesFromAPI, token]);
30712
30782
  (0, import_react41.useEffect)(() => {
30713
- const isAuthenticated = authenticationService.isAuthenticated();
30783
+ const isAuthenticated = authenticationService2.isAuthenticated();
30714
30784
  if (packageSettings?.gatewayApiUrl && availableVoices.length === 0 && !initialized) {
30715
30785
  if (token && isAuthenticated) {
30716
30786
  debugLogger.debug("Chat: Gateway URL available and no voices loaded, attempting to load from API");
@@ -30732,6 +30802,7 @@ var init_chat2 = __esm({
30732
30802
  const [isMobile, setIsMobile] = (0, import_react41.useState)(false);
30733
30803
  const [drawerOpen, setDrawerOpen] = (0, import_react41.useState)(false);
30734
30804
  const [mobileConversationsOpen, setMobileConversationsOpen] = (0, import_react41.useState)(false);
30805
+ const cardSwipeStartXRef = (0, import_react41.useRef)(null);
30735
30806
  (0, import_react41.useEffect)(() => {
30736
30807
  if (typeof document === "undefined") return;
30737
30808
  const meta = document.querySelector('meta[name="theme-color"]');
@@ -31606,7 +31677,12 @@ var init_chat2 = __esm({
31606
31677
  // reads as full physical height with the rounded corner visible
31607
31678
  // where it overlaps the drawer.
31608
31679
  transform: isMobile && mobileConversationsOpen ? "translateX(calc(min(calc(100vw - 56px), 360px) - 12px))" : "none",
31609
- borderRadius: isMobile && mobileConversationsOpen ? "44px" : 0,
31680
+ // Square top-left + no top border: the card's edge runs unbroken
31681
+ // from the very top of the screen (all surfaces share one color),
31682
+ // which reads as true full height; a soft bottom-left corner keeps
31683
+ // the sheet feel.
31684
+ borderRadius: isMobile && mobileConversationsOpen ? "0 0 0 28px" : 0,
31685
+ borderTop: isMobile && mobileConversationsOpen ? "none" : void 0,
31610
31686
  zIndex: isMobile && mobileConversationsOpen ? theme.zIndex.modal + 1 : 0,
31611
31687
  // Hairline border so the rounded card reads even when the backdrop
31612
31688
  // is the same near-black as the shell.
@@ -31619,6 +31695,20 @@ var init_chat2 = __esm({
31619
31695
  setMobileConversationsOpen(false);
31620
31696
  }
31621
31697
  } : void 0,
31698
+ onTouchStart: isMobile && mobileConversationsOpen ? (e) => {
31699
+ if (e.currentTarget.contains(e.target)) {
31700
+ cardSwipeStartXRef.current = e.touches[0]?.clientX ?? null;
31701
+ }
31702
+ } : void 0,
31703
+ onTouchMove: isMobile && mobileConversationsOpen ? (e) => {
31704
+ const start = cardSwipeStartXRef.current;
31705
+ if (start === null) return;
31706
+ const dx = (e.touches[0]?.clientX ?? start) - start;
31707
+ if (Math.abs(dx) > 40) {
31708
+ cardSwipeStartXRef.current = null;
31709
+ setMobileConversationsOpen(false);
31710
+ }
31711
+ } : void 0,
31622
31712
  children: [
31623
31713
  /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
31624
31714
  chat_app_bar_default,
@@ -31916,12 +32006,12 @@ var init_chat2 = __esm({
31916
32006
  ossConfigured,
31917
32007
  isOSSMode: isOSSMode(),
31918
32008
  tier: featureFlag.getEvaluation()?.tier,
31919
- hasToken: authenticationService.isAuthenticated(),
32009
+ hasToken: authenticationService2.isAuthenticated(),
31920
32010
  playgroundBypassAuth,
31921
32011
  isPlaygroundRoute,
31922
32012
  bypassAuth
31923
32013
  });
31924
- if (!allowUnauthenticated && !bypassAuth && !authenticationService.isAuthenticated()) {
32014
+ if (!allowUnauthenticated && !bypassAuth && !authenticationService2.isAuthenticated()) {
31925
32015
  debugLogger.debug("User is not authenticated, redirecting to login");
31926
32016
  return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_react_router_dom4.Navigate, { to: "/login", replace: true });
31927
32017
  }
@@ -31957,7 +32047,7 @@ __export(index_exports, {
31957
32047
  VectorDatabaseService: () => VectorDatabaseService,
31958
32048
  VectorMigrationService: () => VectorMigrationService,
31959
32049
  VoiceService: () => VoiceService,
31960
- authenticationService: () => authenticationService,
32050
+ authenticationService: () => authenticationService2,
31961
32051
  debugLogger: () => debugLogger,
31962
32052
  defineCustomElement: () => defineCustomElement,
31963
32053
  featureFlagService: () => featureFlagService,
@@ -32104,7 +32194,7 @@ var AIProviderInitService = class _AIProviderInitService {
32104
32194
  type: "ollama" /* OLLAMA */,
32105
32195
  baseUrl: settings.ollamaUrl,
32106
32196
  tokenFactory: () => {
32107
- let token = authenticationService.getToken();
32197
+ let token = authenticationService2.getToken();
32108
32198
  if (!token) {
32109
32199
  token = localStorage.getItem("authToken");
32110
32200
  }
@@ -32145,7 +32235,7 @@ var AIProviderInitService = class _AIProviderInitService {
32145
32235
  type: "ollama" /* OLLAMA */,
32146
32236
  baseUrl: settings.ollamaUrl || "http://localhost:11434",
32147
32237
  tokenFactory: () => {
32148
- let token = authenticationService.getToken();
32238
+ let token = authenticationService2.getToken();
32149
32239
  if (!token) {
32150
32240
  token = localStorage.getItem("authToken");
32151
32241
  }
@@ -32176,7 +32266,7 @@ var AIProviderInitService = class _AIProviderInitService {
32176
32266
  type: "ollama" /* OLLAMA */,
32177
32267
  baseUrl: "http://localhost:11434",
32178
32268
  tokenFactory: () => {
32179
- let token = authenticationService.getToken();
32269
+ let token = authenticationService2.getToken();
32180
32270
  if (!token) {
32181
32271
  token = localStorage.getItem("authToken");
32182
32272
  }
@@ -32266,7 +32356,7 @@ var AIProviderInitService = class _AIProviderInitService {
32266
32356
  return config;
32267
32357
  }
32268
32358
  config.tokenFactory = () => {
32269
- let token = authenticationService.getToken();
32359
+ let token = authenticationService2.getToken();
32270
32360
  if (!token && typeof localStorage !== "undefined") {
32271
32361
  try {
32272
32362
  token = localStorage.getItem("authToken");
@@ -32323,11 +32413,11 @@ var ChatProvider = (props) => {
32323
32413
  } catch (error) {
32324
32414
  debugLogger.error("Failed to initialize AI provider:", { error });
32325
32415
  }
32326
- const token = authenticationService.getToken();
32327
- if (token && !authenticationService.isTokenExpired(token)) {
32328
- authenticationService.setToken(token);
32416
+ const token = authenticationService2.getToken();
32417
+ if (token && !authenticationService2.isTokenExpired(token)) {
32418
+ authenticationService2.setToken(token);
32329
32419
  } else {
32330
- authenticationService.clearToken();
32420
+ authenticationService2.clearToken();
32331
32421
  }
32332
32422
  useConversationStore.getState().hydrate();
32333
32423
  useProjectStore.getState().hydrate();
@@ -37258,7 +37348,7 @@ var useGatewayClient = () => {
37258
37348
  }
37259
37349
  return new GatewayService(
37260
37350
  gatewayUrl,
37261
- () => authenticationService.getToken(),
37351
+ () => authenticationService2.getToken(),
37262
37352
  feedbackEmail
37263
37353
  );
37264
37354
  }, [gatewayUrl, feedbackEmail]);
@@ -41137,7 +41227,7 @@ var buildHeaders2 = () => {
41137
41227
  const headers = {
41138
41228
  "Content-Type": "application/json"
41139
41229
  };
41140
- const token = authenticationService.getToken();
41230
+ const token = authenticationService2.getToken();
41141
41231
  if (token) {
41142
41232
  headers.Authorization = `Bearer ${token}`;
41143
41233
  }
@@ -44268,7 +44358,7 @@ function buildUrl3(path) {
44268
44358
  }
44269
44359
  function authHeaders2() {
44270
44360
  const headers = { "Content-Type": "application/json" };
44271
- const token = authenticationService.getToken();
44361
+ const token = authenticationService2.getToken();
44272
44362
  if (token) headers["Authorization"] = `Bearer ${token}`;
44273
44363
  return headers;
44274
44364
  }
@@ -45613,7 +45703,7 @@ var Management = () => {
45613
45703
  let isActive = true;
45614
45704
  const loadCapabilities = async () => {
45615
45705
  try {
45616
- const token = authToken ?? authenticationService.getToken();
45706
+ const token = authToken ?? authenticationService2.getToken();
45617
45707
  const headers = {
45618
45708
  "Content-Type": "application/json"
45619
45709
  };
@@ -45749,7 +45839,7 @@ var Management = () => {
45749
45839
  "admin",
45750
45840
  "platform_admin"
45751
45841
  ]);
45752
- const userRoles = (authenticationService.parseJwtClaims(authenticationService.getToken() ?? "")?.roles ?? []).map((r) => r.toLowerCase());
45842
+ const userRoles = (authenticationService2.parseJwtClaims(authenticationService2.getToken() ?? "")?.roles ?? []).map((r) => r.toLowerCase());
45753
45843
  const isWorkspaceAdmin = userRoles.some(
45754
45844
  (r) => platformAdminRoles.has(r) || r.endsWith("-admin")
45755
45845
  );
@@ -46568,7 +46658,7 @@ var useVoices = () => {
46568
46658
  const gatewayApiUrl = usePackageSettingsStore((state) => state.settings?.gatewayApiUrl);
46569
46659
  const { token } = useAuthenticationStore();
46570
46660
  (0, import_react68.useEffect)(() => {
46571
- const isAuthenticated = authenticationService.isAuthenticated();
46661
+ const isAuthenticated = authenticationService2.isAuthenticated();
46572
46662
  if (gatewayApiUrl && token && isAuthenticated && !isServiceAvailable) {
46573
46663
  debugLogger.debug("Gateway API URL and JWT token available, loading voice models...");
46574
46664
  loadVoicesFromAPI();