@shuffleio/shuffle-mcps 0.0.32 → 0.0.33

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.
package/dist/index.mjs CHANGED
@@ -1808,7 +1808,9 @@ import {
1808
1808
  Pencil as EditIcon,
1809
1809
  ChevronDown as ExpandMoreIcon,
1810
1810
  Lock as LockIcon,
1811
- BookOpen as MenuBookIcon
1811
+ BookOpen as MenuBookIcon,
1812
+ Eye as EyeIcon,
1813
+ EyeOff as EyeOffIcon
1812
1814
  } from "lucide-react";
1813
1815
  import {
1814
1816
  Box as Box3,
@@ -2049,6 +2051,8 @@ var AppAuthCard = ({
2049
2051
  hideDocsLink,
2050
2052
  hideUrlFields,
2051
2053
  borderless,
2054
+ compactAuthForm,
2055
+ extraFieldsSlot,
2052
2056
  globalUrl,
2053
2057
  userdata,
2054
2058
  isLoaded,
@@ -2115,10 +2119,6 @@ var AppAuthCard = ({
2115
2119
  if (!alreadyValid && newestId !== autoTestFiredRef.current) {
2116
2120
  autoTestFiredRef.current = newestId;
2117
2121
  setTimeout(() => {
2118
- toast({
2119
- title: "Auto-testing new authentication",
2120
- description: `Verifying connection for ${app.name.replace(/_/g, " ")}...`
2121
- });
2122
2122
  setTestingAuthId(newestId);
2123
2123
  onTestConnection(app.objectID, newestId);
2124
2124
  }, 500);
@@ -2180,11 +2180,17 @@ var AppAuthCard = ({
2180
2180
  executionId: authState.executionId,
2181
2181
  errorCode: authState.errorCode
2182
2182
  });
2183
+ if (autoTestFiredRef.current === testingAuthId) {
2184
+ setSelectedAuthId(ADD_NEW_AUTH);
2185
+ setUserHasSelected(true);
2186
+ setPendingFailedAuthId(testingAuthId);
2187
+ autoTestFiredRef.current = null;
2188
+ }
2183
2189
  setTestingAuthId(null);
2184
2190
  }
2185
2191
  }, [authState.status, authState.errorMessage, authState.successMessage, authState.warningMessage, testingAuthId, apiAuthEntries, wasPreValidatedPerAuth]);
2186
2192
  const isCredentialError = localTestMessages.errorCode === 401 || localTestMessages.errorCode === 403;
2187
- const showAddNewForm = selectedAuthId === ADD_NEW_AUTH;
2193
+ const showAddNewForm = compactAuthForm ? true : selectedAuthId === ADD_NEW_AUTH;
2188
2194
  const isConfigured = selectedAuth?.active === true;
2189
2195
  const isTested = selectedAuth?.validation?.valid === true;
2190
2196
  const getLastValidTimestamp = () => {
@@ -2206,6 +2212,8 @@ var AppAuthCard = ({
2206
2212
  });
2207
2213
  };
2208
2214
  const [localCredentials, setLocalCredentials] = useState5(authState.credentials || {});
2215
+ const [revealedFields, setRevealedFields] = useState5({});
2216
+ const [pendingFailedAuthId, setPendingFailedAuthId] = useState5(null);
2209
2217
  const [fieldErrors, setFieldErrors] = useState5({});
2210
2218
  const [loading, setLoading] = useState5(false);
2211
2219
  const [saving, setSaving] = useState5(false);
@@ -2281,7 +2289,8 @@ var AppAuthCard = ({
2281
2289
  for (const [k, v] of Object.entries(incoming)) {
2282
2290
  const lk = k.toLowerCase();
2283
2291
  const isUrlish = lk.includes("url") || lk.includes("endpoint") || lk.includes("host");
2284
- if (isUrlish && typeof v === "string" && v !== prev[k]) {
2292
+ const isModel = lk === "model";
2293
+ if ((isUrlish || isModel) && typeof v === "string" && v !== prev[k]) {
2285
2294
  next[k] = v;
2286
2295
  changed = true;
2287
2296
  }
@@ -2477,7 +2486,7 @@ var AppAuthCard = ({
2477
2486
  sx: {
2478
2487
  "& .MuiOutlinedInput-root": {
2479
2488
  backgroundColor: "hsl(var(--background))",
2480
- borderRadius: 2,
2489
+ borderRadius: 1,
2481
2490
  "& fieldset": { borderColor: "hsl(var(--border))" },
2482
2491
  "&:hover fieldset": { borderColor: "hsl(var(--border) / 0.8)" },
2483
2492
  "&.Mui-focused fieldset": { borderColor: "hsl(var(--primary))" }
@@ -2500,7 +2509,7 @@ var AppAuthCard = ({
2500
2509
  sx: {
2501
2510
  "& .MuiOutlinedInput-root": {
2502
2511
  backgroundColor: "hsl(var(--background))",
2503
- borderRadius: 2,
2512
+ borderRadius: 1,
2504
2513
  "& fieldset": { borderColor: "hsl(var(--border))" },
2505
2514
  "&:hover fieldset": { borderColor: "hsl(var(--border) / 0.8)" },
2506
2515
  "&.Mui-focused fieldset": { borderColor: "hsl(var(--primary))" }
@@ -2525,7 +2534,7 @@ var AppAuthCard = ({
2525
2534
  displayEmpty: true,
2526
2535
  sx: {
2527
2536
  backgroundColor: "action.hover",
2528
- borderRadius: 2,
2537
+ borderRadius: 1,
2529
2538
  color: "text.primary",
2530
2539
  "& .MuiOutlinedInput-notchedOutline": { borderColor: "divider" },
2531
2540
  "&:hover .MuiOutlinedInput-notchedOutline": { borderColor: "text.disabled" },
@@ -2570,6 +2579,7 @@ var AppAuthCard = ({
2570
2579
  const fieldKey = param.id || param.name || `param_${index}`;
2571
2580
  const lowerName = (param.name || "").toLowerCase();
2572
2581
  const isSecretField = lowerName.includes("password") || lowerName.includes("secret") || lowerName.includes("key") || lowerName.includes("token");
2582
+ const isRevealed = !!revealedFields[fieldKey];
2573
2583
  return /* @__PURE__ */ jsx6(
2574
2584
  TextField,
2575
2585
  {
@@ -2600,13 +2610,25 @@ var AppAuthCard = ({
2600
2610
  onFocus: (e) => {
2601
2611
  e.target.removeAttribute("readonly");
2602
2612
  }
2603
- }
2613
+ },
2614
+ input: isSecretField ? {
2615
+ endAdornment: /* @__PURE__ */ jsx6(
2616
+ IconButton2,
2617
+ {
2618
+ size: "small",
2619
+ onClick: () => setRevealedFields((prev) => ({ ...prev, [fieldKey]: !prev[fieldKey] })),
2620
+ "aria-label": isRevealed ? `Hide ${param.name}` : `Show ${param.name}`,
2621
+ sx: { color: "hsl(var(--muted-foreground))", "&:hover": { color: "hsl(var(--foreground))" } },
2622
+ children: isRevealed ? /* @__PURE__ */ jsx6(EyeOffIcon, { size: 16 }) : /* @__PURE__ */ jsx6(EyeIcon, { size: 16 })
2623
+ }
2624
+ )
2625
+ } : void 0
2604
2626
  },
2605
2627
  name: `auth-${fieldKey}-${app.objectID}-${Math.random().toString(36).slice(2, 8)}`,
2606
2628
  sx: {
2607
2629
  "& .MuiOutlinedInput-root": {
2608
2630
  backgroundColor: isSecretField ? "hsl(var(--primary) / 0.06)" : "hsl(var(--muted))",
2609
- borderRadius: 2,
2631
+ borderRadius: 1,
2610
2632
  "& fieldset": {
2611
2633
  borderColor: fieldErrors[fieldKey] ? "hsl(var(--destructive))" : isSecretField ? "hsl(var(--primary) / 0.5)" : "hsl(var(--border))",
2612
2634
  borderWidth: isSecretField ? 2 : 1
@@ -2618,7 +2640,7 @@ var AppAuthCard = ({
2618
2640
  },
2619
2641
  "& .MuiInputBase-input": {
2620
2642
  color: "hsl(var(--foreground))",
2621
- ...isSecretField && {
2643
+ ...isSecretField && !isRevealed && {
2622
2644
  WebkitTextSecurity: "disc",
2623
2645
  textSecurity: "disc",
2624
2646
  fontFamily: "text-security-disc, monospace"
@@ -2669,7 +2691,6 @@ var AppAuthCard = ({
2669
2691
  setSaveSuccess(success);
2670
2692
  if (success) {
2671
2693
  setUserHasSelected(false);
2672
- setLocalCredentials({});
2673
2694
  setFieldErrors({});
2674
2695
  }
2675
2696
  };
@@ -2877,7 +2898,7 @@ var AppAuthCard = ({
2877
2898
  borderTop: borderless ? "none" : "1px solid hsl(var(--border))"
2878
2899
  },
2879
2900
  children: [
2880
- apiAuthEntries.length > 0 && /* @__PURE__ */ jsxs4(Box3, { sx: { mb: 3 }, children: [
2901
+ !compactAuthForm && apiAuthEntries.length > 0 && /* @__PURE__ */ jsxs4(Box3, { sx: { mb: 3 }, children: [
2881
2902
  /* @__PURE__ */ jsx6(Typography3, { variant: "body2", sx: { color: "hsl(var(--muted-foreground))", mb: 1 }, children: "Select authentication" }),
2882
2903
  /* @__PURE__ */ jsx6(FormControl, { fullWidth: true, size: "small", children: /* @__PURE__ */ jsxs4(
2883
2904
  Select,
@@ -3416,7 +3437,7 @@ var AppAuthCard = ({
3416
3437
  children: /* @__PURE__ */ jsx6(Typography3, { sx: { fontSize: "0.875rem" }, children: localTestMessages.errorCode === 401 ? "Previous credentials were invalid or expired. Please enter new credentials." : "Access was denied with the previous credentials. Please re-authenticate with valid permissions." })
3417
3438
  }
3418
3439
  ),
3419
- /* @__PURE__ */ jsx6(Typography3, { variant: "subtitle2", sx: { color: "hsl(var(--foreground))", fontWeight: 600, mb: 2 }, children: apiAuthEntries.length === 0 ? "Configure Authentication" : "Add New Authentication" }),
3440
+ /* @__PURE__ */ jsx6(Typography3, { variant: "subtitle2", sx: { color: "hsl(var(--foreground))", fontWeight: 600, mb: 2 }, children: apiAuthEntries.length === 0 ? `Configure ${app.name.replace(/_/g, " ")}` : "Add New Authentication" }),
3420
3441
  loading ? /* @__PURE__ */ jsxs4(Box3, { sx: { display: "flex", alignItems: "center", justifyContent: "center", py: 4 }, children: [
3421
3442
  /* @__PURE__ */ jsx6(CircularProgress2, { size: 32, sx: { color: "hsl(var(--primary))" } }),
3422
3443
  /* @__PURE__ */ jsx6(Typography3, { sx: { ml: 2, color: "hsl(var(--muted-foreground))" }, children: "Loading configuration..." })
@@ -3452,6 +3473,7 @@ var AppAuthCard = ({
3452
3473
  ] })
3453
3474
  }
3454
3475
  ) : /* @__PURE__ */ jsxs4(Box3, { sx: { display: "flex", flexDirection: "column", gap: 3 }, children: [
3476
+ extraFieldsSlot?.({ credentials: localCredentials, setField: handleCredentialChange }),
3455
3477
  renderOAuth2Fields(),
3456
3478
  renderParameterFields(),
3457
3479
  authState.status === "error" && authState.errorMessage && /* @__PURE__ */ jsx6(
@@ -3506,38 +3528,97 @@ var AppAuthCard = ({
3506
3528
  children: "Failed to save authentication. Please try again."
3507
3529
  }
3508
3530
  ),
3509
- !isOAuth2 && /* @__PURE__ */ jsx6(Box3, { sx: { display: "flex", justifyContent: "flex-end", pt: 1.5 }, children: /* @__PURE__ */ jsx6(
3510
- Button2,
3511
- {
3512
- variant: "outlined",
3513
- size: "medium",
3514
- onClick: (e) => {
3515
- e.stopPropagation();
3516
- handleSave();
3517
- },
3518
- disabled: saving || !isFormValid(),
3519
- sx: {
3520
- borderColor: isFormValid() ? "hsl(var(--primary) / 0.5)" : "hsl(var(--border))",
3521
- color: isFormValid() ? "hsl(var(--primary))" : "hsl(var(--muted-foreground))",
3522
- fontWeight: 600,
3523
- textTransform: "none",
3524
- fontSize: "0.9rem",
3525
- px: 3,
3526
- py: 1,
3527
- borderRadius: 2,
3528
- transition: "all 0.2s ease",
3529
- "&:hover": {
3530
- borderColor: "hsl(var(--primary))",
3531
- backgroundColor: "hsl(var(--primary) / 0.08)"
3531
+ !isOAuth2 && /* @__PURE__ */ jsxs4(Box3, { sx: { display: "flex", justifyContent: "flex-end", pt: 1.5, gap: 1, flexWrap: "wrap" }, children: [
3532
+ pendingFailedAuthId && /* @__PURE__ */ jsx6(
3533
+ Button2,
3534
+ {
3535
+ variant: "text",
3536
+ size: "medium",
3537
+ onClick: async (e) => {
3538
+ e.stopPropagation();
3539
+ const previousFailedId = pendingFailedAuthId;
3540
+ setPendingFailedAuthId(null);
3541
+ setUserHasSelected(true);
3542
+ setFieldErrors({});
3543
+ await onSaveAuth(app.objectID, localCredentials);
3544
+ let entries = apiAuthEntries;
3545
+ if (onRefreshAuth) {
3546
+ await onRefreshAuth();
3547
+ }
3548
+ entries = apiAuthEntries || [];
3549
+ const sorted = [...entries].sort((a, b) => (b.created || 0) - (a.created || 0));
3550
+ const acceptId = sorted[0]?.id || previousFailedId;
3551
+ setSelectedAuthId(acceptId);
3552
+ const stale = entries.filter((e2) => e2.id && e2.id !== acceptId);
3553
+ await Promise.all(stale.map(async (entry) => {
3554
+ try {
3555
+ await fetch(getApiUrl(`/api/v1/apps/authentication/${entry.id}`), {
3556
+ method: "DELETE",
3557
+ credentials: "include",
3558
+ headers: { ...getAuthHeader() }
3559
+ });
3560
+ } catch (err) {
3561
+ console.error("[AppAuthCard] Failed to delete stale auth on Save anyway:", err);
3562
+ }
3563
+ }));
3564
+ if (onRefreshAuth) await onRefreshAuth();
3565
+ if (onSelectAuth) onSelectAuth(app.objectID, acceptId);
3566
+ if (typeof window !== "undefined") {
3567
+ window.dispatchEvent(new CustomEvent("integrations-changed"));
3568
+ window.dispatchEvent(new CustomEvent("agent-drawer-close"));
3569
+ }
3532
3570
  },
3533
- "&.Mui-disabled": {
3534
- borderColor: "hsl(var(--border))",
3535
- color: "hsl(var(--muted-foreground))"
3536
- }
3537
- },
3538
- children: saving ? "Saving..." : "Save Authentication"
3539
- }
3540
- ) }),
3571
+ sx: {
3572
+ color: "hsl(var(--muted-foreground))",
3573
+ fontWeight: 600,
3574
+ textTransform: "none",
3575
+ fontSize: "0.85rem",
3576
+ px: 2,
3577
+ py: 1,
3578
+ borderRadius: 2,
3579
+ "&:hover": {
3580
+ color: "hsl(var(--foreground))",
3581
+ backgroundColor: "hsl(var(--muted) / 0.5)"
3582
+ }
3583
+ },
3584
+ title: "Our test isn't always authoritative \u2014 keep the credentials you saved and dismiss the failure.",
3585
+ children: "Save anyway"
3586
+ }
3587
+ ),
3588
+ /* @__PURE__ */ jsx6(
3589
+ Button2,
3590
+ {
3591
+ variant: "outlined",
3592
+ size: "medium",
3593
+ onClick: (e) => {
3594
+ e.stopPropagation();
3595
+ setPendingFailedAuthId(null);
3596
+ handleSave();
3597
+ },
3598
+ disabled: saving || !isFormValid(),
3599
+ sx: {
3600
+ borderColor: isFormValid() ? "hsl(var(--primary) / 0.5)" : "hsl(var(--border))",
3601
+ color: isFormValid() ? "hsl(var(--primary))" : "hsl(var(--muted-foreground))",
3602
+ fontWeight: 600,
3603
+ textTransform: "none",
3604
+ fontSize: "0.9rem",
3605
+ px: 3,
3606
+ py: 1,
3607
+ borderRadius: 2,
3608
+ transition: "all 0.2s ease",
3609
+ "&:hover": {
3610
+ borderColor: "hsl(var(--primary))",
3611
+ backgroundColor: "hsl(var(--primary) / 0.08)"
3612
+ },
3613
+ "&.Mui-disabled": {
3614
+ borderColor: "hsl(var(--border))",
3615
+ color: "hsl(var(--muted-foreground))"
3616
+ }
3617
+ },
3618
+ children: saving ? "Testing..." : pendingFailedAuthId ? "Retry Test" : "Test Authentication"
3619
+ }
3620
+ )
3621
+ ] }),
3541
3622
  isOAuth2 && (() => {
3542
3623
  const hasClientId = !!localCredentials["client_id"]?.trim();
3543
3624
  const hasClientSecret = !!localCredentials["client_secret"]?.trim();
@@ -5641,28 +5722,38 @@ function AppDetailDrawer({
5641
5722
  }
5642
5723
  }, [open, appName]);
5643
5724
  const isLoadingAll = appLoading || isAuthenticated && appAuthLoading;
5725
+ const drawerWidth = `min(${width}px, 100vw)`;
5644
5726
  return /* @__PURE__ */ jsxs9(
5645
5727
  Drawer,
5646
5728
  {
5647
5729
  anchor,
5648
5730
  open,
5649
5731
  onClose: handleClose,
5650
- slotProps: {
5651
- paper: {
5652
- className: scopeClassName,
5653
- sx: {
5654
- width: { xs: "100%", sm: width },
5655
- maxWidth: "100vw",
5656
- display: "flex",
5657
- flexDirection: "column",
5658
- background: "linear-gradient(180deg, hsl(var(--card)) 0%, hsl(var(--background)) 100%)",
5659
- borderLeft: anchor === "right" ? "1px solid hsl(var(--border))" : "none",
5660
- borderRight: anchor === "left" ? "1px solid hsl(var(--border))" : "none"
5661
- }
5732
+ PaperProps: {
5733
+ className: scopeClassName,
5734
+ sx: {
5735
+ width: drawerWidth,
5736
+ minWidth: drawerWidth,
5737
+ maxWidth: drawerWidth,
5738
+ flex: `0 0 ${drawerWidth}`,
5739
+ height: "100vh",
5740
+ display: "flex",
5741
+ flexDirection: "column",
5742
+ overflow: "hidden",
5743
+ background: "linear-gradient(180deg, hsl(var(--card)) 0%, hsl(var(--background)) 100%)",
5744
+ borderLeft: anchor === "right" ? "1px solid hsl(var(--border))" : "none",
5745
+ borderRight: anchor === "left" ? "1px solid hsl(var(--border))" : "none"
5662
5746
  }
5663
5747
  },
5664
5748
  sx: {
5665
- "& .MuiDrawer-paper": { boxSizing: "border-box" }
5749
+ zIndex: 9999,
5750
+ "& .MuiDrawer-paper": {
5751
+ boxSizing: "border-box",
5752
+ width: `${drawerWidth} !important`,
5753
+ minWidth: `${drawerWidth} !important`,
5754
+ maxWidth: `${drawerWidth} !important`,
5755
+ flex: `0 0 ${drawerWidth} !important`
5756
+ }
5666
5757
  },
5667
5758
  children: [
5668
5759
  /* @__PURE__ */ jsxs9(
@@ -6695,6 +6786,7 @@ function AppSearchDrawer({
6695
6786
  const t = setTimeout(() => setHighlightActive(true), highlightDelayMs);
6696
6787
  return () => clearTimeout(t);
6697
6788
  }, [open, highlightAppName, highlightDelayMs]);
6789
+ const drawerWidth = `min(${width}px, 100vw)`;
6698
6790
  const handleClose = () => {
6699
6791
  setDetailAppName(null);
6700
6792
  setDetailAppId(null);
@@ -6771,29 +6863,38 @@ function AppSearchDrawer({
6771
6863
  anchor,
6772
6864
  open: open && detailAppName === null,
6773
6865
  onClose: handleClose,
6774
- slotProps: {
6775
- paper: {
6776
- className: scopeClassName,
6777
- sx: {
6778
- // Strict, environment-independent sizing so the drawer
6779
- // looks identical on every host (Shuffle Security, /agents,
6780
- // test page, embedded library, etc.). No breakpoint variance.
6781
- width: `min(${width}px, 100vw)`,
6782
- minWidth: `min(${width}px, 100vw)`,
6783
- maxWidth: "100vw",
6784
- height: "100vh",
6785
- display: "flex",
6786
- flexDirection: "column",
6787
- overflow: "hidden",
6788
- background: "linear-gradient(180deg, hsl(var(--card)) 0%, hsl(var(--background)) 100%)",
6789
- borderLeft: anchor === "right" ? "1px solid hsl(var(--border))" : "none",
6790
- borderRight: anchor === "left" ? "1px solid hsl(var(--border))" : "none"
6791
- }
6866
+ PaperProps: {
6867
+ className: scopeClassName,
6868
+ sx: {
6869
+ // Strict, environment-independent sizing so the drawer
6870
+ // looks identical on every host (Shuffle Security, /agents,
6871
+ // test page, embedded library, etc.). No breakpoint variance.
6872
+ // NOTE: use PaperProps (not slotProps.paper) — slotProps.paper
6873
+ // was added in MUI v6 and is silently ignored on MUI v5 hosts,
6874
+ // which made the drawer collapse to content width when
6875
+ // consumed from the published library.
6876
+ width: drawerWidth,
6877
+ minWidth: drawerWidth,
6878
+ maxWidth: drawerWidth,
6879
+ flex: `0 0 ${drawerWidth}`,
6880
+ height: "100vh",
6881
+ display: "flex",
6882
+ flexDirection: "column",
6883
+ overflow: "hidden",
6884
+ background: "linear-gradient(180deg, hsl(var(--card)) 0%, hsl(var(--background)) 100%)",
6885
+ borderLeft: anchor === "right" ? "1px solid hsl(var(--border))" : "none",
6886
+ borderRight: anchor === "left" ? "1px solid hsl(var(--border))" : "none"
6792
6887
  }
6793
6888
  },
6794
6889
  sx: {
6795
6890
  zIndex: 9999,
6796
- "& .MuiDrawer-paper": { boxSizing: "border-box" }
6891
+ "& .MuiDrawer-paper": {
6892
+ boxSizing: "border-box",
6893
+ width: `${drawerWidth} !important`,
6894
+ minWidth: `${drawerWidth} !important`,
6895
+ maxWidth: `${drawerWidth} !important`,
6896
+ flex: `0 0 ${drawerWidth} !important`
6897
+ }
6797
6898
  },
6798
6899
  children: [
6799
6900
  /* @__PURE__ */ jsxs12(
@@ -6825,7 +6926,7 @@ function AppSearchDrawer({
6825
6926
  ]
6826
6927
  }
6827
6928
  ),
6828
- /* @__PURE__ */ jsxs12(Box9, { sx: { flex: 1, boxSizing: "border-box", overflow: "hidden", p: 3, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
6929
+ /* @__PURE__ */ jsxs12(Box9, { sx: { flex: 1, width: "100%", minWidth: 0, boxSizing: "border-box", overflow: "hidden", p: 3, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
6829
6930
  connectionPathApps && connectionPathApps.length > 0 && /* @__PURE__ */ jsxs12(Box9, { sx: { mb: 2.5 }, children: [
6830
6931
  /* @__PURE__ */ jsx15(Typography9, { sx: { color: "hsl(var(--muted-foreground))", fontSize: "0.7rem", fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.05em", mb: 1 }, children: "In this usecase" }),
6831
6932
  /* @__PURE__ */ jsx15(Box9, { sx: { display: "flex", gap: 1.5, flexWrap: "wrap" }, children: connectionPathApps.map((app) => /* @__PURE__ */ jsx15(Tooltip5, { title: app.name.replace(/_/g, " "), arrow: true, placement: "bottom", children: /* @__PURE__ */ jsxs12(
@@ -6872,6 +6973,8 @@ function AppSearchDrawer({
6872
6973
  {
6873
6974
  sx: {
6874
6975
  flex: 1,
6976
+ width: "100%",
6977
+ minWidth: 0,
6875
6978
  minHeight: 0,
6876
6979
  overflow: "hidden",
6877
6980
  "& .singul-container, & .singul-search-bar-container": {
@@ -6884,16 +6987,22 @@ function AppSearchDrawer({
6884
6987
  },
6885
6988
  "& .singul-results-container": {
6886
6989
  flex: 1,
6990
+ width: "100%",
6991
+ minWidth: 0,
6887
6992
  minHeight: 0,
6888
6993
  maxHeight: "none",
6889
6994
  overflowY: "auto"
6890
6995
  },
6891
6996
  "& .singul-results-grid": {
6997
+ width: "100% !important",
6998
+ minWidth: "0 !important",
6892
6999
  gridTemplateColumns: "repeat(2, minmax(0, 1fr)) !important",
6893
7000
  gridAutoRows: "78px !important",
6894
7001
  gap: "12px !important"
6895
7002
  },
6896
7003
  "& .singul-results-grid .singul-dropdown-item": {
7004
+ width: "100%",
7005
+ maxWidth: "100%",
6897
7006
  minWidth: 0,
6898
7007
  minHeight: "78px !important",
6899
7008
  maxHeight: "78px !important",
@@ -7695,6 +7804,73 @@ function invalidateResolvedApps() {
7695
7804
  _cache.clear();
7696
7805
  }
7697
7806
 
7807
+ // llmProviderDetect.ts
7808
+ var SHUFFLE_AI_PRESET = "Shuffle AI";
7809
+ var CUSTOM_PRESET = "Custom / self-hosted";
7810
+ var ENDPOINT_PRESETS = [
7811
+ { label: SHUFFLE_AI_PRESET, url: "" },
7812
+ { label: "OpenAI", url: "https://api.openai.com/v1", apiKeyUrl: "https://platform.openai.com/api-keys", apiKeyHint: "Create a key under API keys in the OpenAI platform dashboard." },
7813
+ { label: "Anthropic", url: "https://api.anthropic.com/v1/", apiKeyUrl: "https://console.anthropic.com/settings/keys", apiKeyHint: "Generate a key under Settings \u2192 API Keys in the Anthropic Console." },
7814
+ { label: "Google Gemini", url: "https://generativelanguage.googleapis.com/v1beta/openai/", apiKeyUrl: "https://aistudio.google.com/app/apikey", apiKeyHint: "Create a key in Google AI Studio under Get API key." },
7815
+ { label: "Mistral", url: "https://api.mistral.ai/v1", apiKeyUrl: "https://console.mistral.ai/api-keys/", apiKeyHint: "Create a key under API Keys in the Mistral Console." },
7816
+ { label: "Groq", url: "https://api.groq.com/openai/v1", apiKeyUrl: "https://console.groq.com/keys", apiKeyHint: "Create a key under API Keys in the Groq Console." },
7817
+ { label: "DeepSeek", url: "https://api.deepseek.com/v1", apiKeyUrl: "https://platform.deepseek.com/api_keys", apiKeyHint: "Create a key under API Keys in the DeepSeek platform." },
7818
+ { label: "Together AI", url: "https://api.together.xyz/v1", apiKeyUrl: "https://api.together.ai/settings/api-keys", apiKeyHint: "Create a key under Settings \u2192 API Keys in Together AI." },
7819
+ { label: "OpenRouter", url: "https://openrouter.ai/api/v1", apiKeyUrl: "https://openrouter.ai/keys", apiKeyHint: "Create a key under Keys in your OpenRouter dashboard." },
7820
+ { label: "Ollama (localhost)", url: "http://localhost:11434/v1", apiKeyHint: "Local Ollama does not require an API key \u2014 any non-empty value works." },
7821
+ { label: "LM Studio (localhost)", url: "http://localhost:1234/v1", apiKeyHint: "Local LM Studio does not require an API key \u2014 any non-empty value works." },
7822
+ { label: CUSTOM_PRESET, url: "" }
7823
+ ];
7824
+ var PROVIDER_DOMAINS = {
7825
+ "Shuffle AI": "shuffler.io",
7826
+ OpenAI: "openai.com",
7827
+ Anthropic: "anthropic.com",
7828
+ "Google Gemini": "gemini.google.com",
7829
+ Mistral: "mistral.ai",
7830
+ Groq: "groq.com",
7831
+ DeepSeek: "deepseek.com",
7832
+ "Together AI": "together.ai",
7833
+ OpenRouter: "openrouter.ai",
7834
+ "Ollama (localhost)": "ollama.com",
7835
+ "LM Studio (localhost)": "lmstudio.ai"
7836
+ };
7837
+ var hostnameOf = (url) => {
7838
+ try {
7839
+ return new URL(url).hostname.replace(/^www\./, "");
7840
+ } catch {
7841
+ return null;
7842
+ }
7843
+ };
7844
+ var detectLLMProvider = (url) => {
7845
+ if (!url) return null;
7846
+ const trimmed = url.trim();
7847
+ if (!trimmed) return null;
7848
+ const exact = ENDPOINT_PRESETS.find((p) => p.url && p.url === trimmed);
7849
+ if (exact) return exact;
7850
+ const host = hostnameOf(trimmed);
7851
+ if (host) {
7852
+ const byHost = ENDPOINT_PRESETS.find((p) => {
7853
+ const presetHost = hostnameOf(p.url);
7854
+ return presetHost && presetHost === host;
7855
+ });
7856
+ if (byHost) return byHost;
7857
+ if (host === "localhost" || host === "127.0.0.1") {
7858
+ if (trimmed.includes(":11434")) return ENDPOINT_PRESETS.find((p) => p.label === "Ollama (localhost)") || null;
7859
+ if (trimmed.includes(":1234")) return ENDPOINT_PRESETS.find((p) => p.label === "LM Studio (localhost)") || null;
7860
+ }
7861
+ }
7862
+ return ENDPOINT_PRESETS.find((p) => p.label === CUSTOM_PRESET) || null;
7863
+ };
7864
+ var getProviderLogoUrl = (label, url) => {
7865
+ if (!label && !url) return "";
7866
+ let domain = label ? PROVIDER_DOMAINS[label] : void 0;
7867
+ if (!domain && url) {
7868
+ const host = hostnameOf(url);
7869
+ if (host) domain = host;
7870
+ }
7871
+ return domain ? `https://www.google.com/s2/favicons?domain=${domain}&sz=64` : "";
7872
+ };
7873
+
7698
7874
  // agentRun.ts
7699
7875
  var resolveTarget = (path, opts = {}) => {
7700
7876
  const url = opts.apiBaseUrl ? `${opts.apiBaseUrl.replace(/\/+$/, "")}${path}` : getApiUrl(path);
@@ -8608,10 +8784,10 @@ var AgentRunDiagnosisBanner = ({ run, sx, onJumpToEvidence, executionId }) => {
8608
8784
  const outputWarning = !isFailed && hasOutputWarning(run);
8609
8785
  const diagnosis = outputWarning ? diagnoseOutputWarning(run) : null;
8610
8786
  if (!failureInfo && !diagnosis) return null;
8611
- const isCritical = !!failureInfo;
8787
+ const isCritical = !!failureInfo || diagnosis?.kind === "token_limit";
8612
8788
  const tone = isCritical ? "critical" : "medium";
8613
8789
  const Icon = isCritical ? AlertTriangle : HelpCircle;
8614
- const message = isCritical ? failureInfo.reason : `${diagnosis.title} \u2014 ${diagnosis.remediation}`;
8790
+ const message = failureInfo ? failureInfo.reason : `${diagnosis.title} \u2014 ${diagnosis.remediation}`;
8615
8791
  const firstEvidence = diagnosis?.evidence?.[0] || null;
8616
8792
  const jumpDecisionIndex = firstEvidence ? extractDecisionIndex(firstEvidence.path) : null;
8617
8793
  const canJump = !!(onJumpToEvidence && jumpDecisionIndex !== null);
@@ -9150,7 +9326,7 @@ var TimelineRow = ({
9150
9326
  ),
9151
9327
  /* @__PURE__ */ jsx20(Box14, { sx: {
9152
9328
  flex: 1,
9153
- minWidth: 0,
9329
+ minWidth: 180,
9154
9330
  fontSize: "0.85rem",
9155
9331
  color: "hsl(var(--foreground))",
9156
9332
  maxHeight: 60,
@@ -9160,7 +9336,7 @@ var TimelineRow = ({
9160
9336
  "& a": { color: "hsl(var(--primary))", textDecoration: "underline", textUnderlineOffset: "2px" },
9161
9337
  "& a:hover": { opacity: 0.85 }
9162
9338
  }, children: /* @__PURE__ */ jsx20(Markdown, { remarkPlugins: [remarkGfm4, remarkBreaks], children: normalizeMarkdown(displayLabel) }) }),
9163
- /* @__PURE__ */ jsx20(Tooltip9, { title: hasTiming ? `Duration: ${dur.toFixed(2)}s \xB7 ${new Date(itemStart * 1e3).toLocaleString()}` : "No timing data", children: /* @__PURE__ */ jsx20(Box14, { sx: { width: maxWidth, position: "relative", height: 10, flexShrink: 0 }, children: dur > 0 && /* @__PURE__ */ jsx20(Box14, { sx: {
9339
+ /* @__PURE__ */ jsx20(Tooltip9, { title: hasTiming ? `Duration: ${dur.toFixed(2)}s \xB7 ${new Date(itemStart * 1e3).toLocaleString()}` : "No timing data", children: /* @__PURE__ */ jsx20(Box14, { sx: { width: maxWidth, maxWidth, minWidth: 40, position: "relative", height: 10, flexShrink: 1, flexBasis: maxWidth }, children: dur > 0 && /* @__PURE__ */ jsx20(Box14, { sx: {
9164
9340
  position: "absolute",
9165
9341
  left: Math.max(0, offset),
9166
9342
  width,
@@ -9568,6 +9744,7 @@ var AgentUI = ({
9568
9744
  const [chosenApps, setChosenApps] = useState12(apps ?? defaultApps ?? BUILTIN_DEFAULT_APPS);
9569
9745
  const [availableApps, setAvailableApps] = useState12([]);
9570
9746
  const [authAppsLoading, setAuthAppsLoading] = useState12(autoLoadApps && hasApiKey);
9747
+ const [detectedLLM, setDetectedLLM] = useState12(null);
9571
9748
  const [executionApps, setExecutionApps] = useState12([]);
9572
9749
  const [resolvedToolApps, setResolvedToolApps] = useState12({});
9573
9750
  const [appSearchOpen, setAppSearchOpen] = useState12(false);
@@ -9602,9 +9779,25 @@ var AgentUI = ({
9602
9779
  const [error, setError] = useState12(null);
9603
9780
  const [searchParams, setSearchParams] = useSearchParams();
9604
9781
  const initialViewParam = searchParams.get("agentView");
9605
- const [viewMode, setViewMode] = useState12(
9606
- initialViewParam === "detailed" ? "detailed" : "simple"
9607
- );
9782
+ const readStoredViewMode = () => {
9783
+ if (initialViewParam === "detailed") return "detailed";
9784
+ if (typeof window === "undefined") return "simple";
9785
+ try {
9786
+ const stored = window.localStorage.getItem("shuffle-agents-view-mode");
9787
+ if (stored === "detailed" || stored === "simple") return stored;
9788
+ } catch {
9789
+ }
9790
+ return "simple";
9791
+ };
9792
+ const [viewMode, setViewMode] = useState12(readStoredViewMode);
9793
+ useEffect11(() => {
9794
+ try {
9795
+ if (typeof window !== "undefined") {
9796
+ window.localStorage.setItem("shuffle-agents-view-mode", viewMode);
9797
+ }
9798
+ } catch {
9799
+ }
9800
+ }, [viewMode]);
9608
9801
  const [attachedImages, setAttachedImages] = useState12([]);
9609
9802
  const [nowTick, setNowTick] = useState12(() => Math.floor(Date.now() / 1e3));
9610
9803
  const [localRunStart, setLocalRunStart] = useState12(null);
@@ -9840,12 +10033,23 @@ var AgentUI = ({
9840
10033
  const list = Array.isArray(result) ? result : result?.data || [];
9841
10034
  const seen = /* @__PURE__ */ new Set();
9842
10035
  const loaded = [];
10036
+ let detectedFromEntries = null;
9843
10037
  for (const entry of list) {
9844
10038
  const app = entry?.app || entry;
9845
10039
  const name = app?.name;
9846
10040
  if (!name) continue;
9847
10041
  const valid = entry?.active || entry?.validation?.valid || entry?.hasValidAuth || app?.is_valid || app?.tested;
9848
10042
  if (valid === false) continue;
10043
+ if (!detectedFromEntries && (name.toLowerCase() === "openai" || app?.id === "5d19dd82517870c68d40cacad9b5ca91")) {
10044
+ const urlField = (entry?.fields || []).find((f) => (f?.key || "").toLowerCase() === "url");
10045
+ const urlVal = (urlField?.value || "").trim();
10046
+ if (urlVal) {
10047
+ const preset = detectLLMProvider(urlVal);
10048
+ if (preset) {
10049
+ detectedFromEntries = { label: preset.label, url: urlVal, logo: getProviderLogoUrl(preset.label, urlVal) };
10050
+ }
10051
+ }
10052
+ }
9849
10053
  const key = normalizeAgentAppName(name);
9850
10054
  if (seen.has(key)) continue;
9851
10055
  seen.add(key);
@@ -9857,6 +10061,7 @@ var AgentUI = ({
9857
10061
  }
9858
10062
  if (signal?.cancelled) return;
9859
10063
  setAvailableApps(loaded);
10064
+ setDetectedLLM(detectedFromEntries);
9860
10065
  } catch {
9861
10066
  } finally {
9862
10067
  if (!signal?.cancelled) setAuthAppsLoading(false);
@@ -10118,7 +10323,12 @@ var AgentUI = ({
10118
10323
  setSimpleSubmitAttempted(false);
10119
10324
  setError(null);
10120
10325
  setLocalRunStart(null);
10121
- setViewMode("simple");
10326
+ try {
10327
+ const stored = typeof window !== "undefined" ? window.localStorage.getItem("shuffle-agents-view-mode") : null;
10328
+ setViewMode(stored === "detailed" ? "detailed" : "simple");
10329
+ } catch {
10330
+ setViewMode("simple");
10331
+ }
10122
10332
  setShowStarter(false);
10123
10333
  userPickedStartRef.current = false;
10124
10334
  if (readUrlParams && typeof window !== "undefined") {
@@ -11558,8 +11768,19 @@ var AgentUI = ({
11558
11768
  "&:hover": { color: "hsl(var(--foreground))", bgcolor: "hsl(var(--muted) / 0.5)" }
11559
11769
  },
11560
11770
  children: [
11561
- /* @__PURE__ */ jsx20(SettingsIcon, { size: 14 }),
11562
- "Choose LLM"
11771
+ detectedLLM?.logo ? /* @__PURE__ */ jsx20(
11772
+ Box14,
11773
+ {
11774
+ component: "img",
11775
+ src: detectedLLM.logo,
11776
+ alt: "",
11777
+ sx: { width: 14, height: 14, borderRadius: "3px", objectFit: "contain", display: "block" },
11778
+ onError: (e) => {
11779
+ e.currentTarget.style.display = "none";
11780
+ }
11781
+ }
11782
+ ) : /* @__PURE__ */ jsx20(SettingsIcon, { size: 14 }),
11783
+ detectedLLM?.label || "Choose LLM"
11563
11784
  ]
11564
11785
  }
11565
11786
  ) }),
@@ -11793,7 +12014,7 @@ var AgentUI = ({
11793
12014
  AgentRunDiagnosisBanner_default,
11794
12015
  {
11795
12016
  run: execution?.results?.length ? execution : agentData,
11796
- sx: { px: 0, pb: 0, mb: 2 },
12017
+ sx: { px: 1.5, pb: 0, mb: 2 },
11797
12018
  executionId: execution?.execution_id,
11798
12019
  onJumpToEvidence: (decisionIndex) => {
11799
12020
  const dec = (agentData?.decisions || [])[decisionIndex];
@@ -12018,14 +12239,14 @@ var AgentUI = ({
12018
12239
  ] })
12019
12240
  ] });
12020
12241
  })() : !finishAnswer && isRunning ? /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "Waiting for the agent to produce the first step." }) : !finishAnswer ? /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "No final answer was returned. Open Detailed to inspect each step." }) : null,
12021
- !isRunning && /* @__PURE__ */ jsx20(Box14, { children: /* @__PURE__ */ jsx20(
12242
+ /* @__PURE__ */ jsx20(Box14, { children: /* @__PURE__ */ jsx20(
12022
12243
  Button8,
12023
12244
  {
12024
12245
  size: "small",
12025
12246
  variant: "text",
12026
12247
  onClick: () => setViewMode("detailed"),
12027
12248
  sx: { color: "hsl(var(--primary))", textTransform: "none", px: 0 },
12028
- children: "View detailed timeline \u2192"
12249
+ children: isRunning ? "View live detailed timeline \u2192" : "View detailed timeline \u2192"
12029
12250
  }
12030
12251
  ) })
12031
12252
  ] });
@@ -12230,7 +12451,7 @@ import {
12230
12451
  } from "lucide-react";
12231
12452
 
12232
12453
  // components/LocalLLMConfig.tsx
12233
- import { useEffect as useEffect12, useMemo as useMemo7, useRef as useRef9, useState as useState13 } from "react";
12454
+ import { useEffect as useEffect12, useMemo as useMemo7, useState as useState13 } from "react";
12234
12455
  import {
12235
12456
  Autocomplete as Autocomplete3,
12236
12457
  Box as Box16,
@@ -12329,8 +12550,6 @@ import { Fragment as Fragment8, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-r
12329
12550
  import { createElement as createElement2 } from "react";
12330
12551
  var OPENAI_APP_NAME = "OpenAI";
12331
12552
  var OPENAI_APP_ID = "5d19dd82517870c68d40cacad9b5ca91";
12332
- var SHUFFLE_AI_PRESET = "Shuffle AI";
12333
- var CUSTOM_PRESET = "Custom / self-hosted";
12334
12553
  var OPENAI_ALGOLIA_APP = {
12335
12554
  name: OPENAI_APP_NAME,
12336
12555
  description: "OpenAI-compatible LLM endpoint for agent operations",
@@ -12350,32 +12569,18 @@ var OPENAI_ALGOLIA_APP = {
12350
12569
  triggers: [],
12351
12570
  verified: true
12352
12571
  };
12353
- var ENDPOINT_PRESETS = [
12354
- { label: SHUFFLE_AI_PRESET, url: "" },
12355
- { label: "OpenAI", url: "https://api.openai.com/v1", apiKeyUrl: "https://platform.openai.com/api-keys", apiKeyHint: "Create a key under API keys in the OpenAI platform dashboard." },
12356
- { label: "Anthropic", url: "https://api.anthropic.com/v1/", apiKeyUrl: "https://console.anthropic.com/settings/keys", apiKeyHint: "Generate a key under Settings \u2192 API Keys in the Anthropic Console." },
12357
- { label: "Google Gemini", url: "https://generativelanguage.googleapis.com/v1beta/openai/", apiKeyUrl: "https://aistudio.google.com/app/apikey", apiKeyHint: "Create a key in Google AI Studio under Get API key." },
12358
- { label: "Mistral", url: "https://api.mistral.ai/v1", apiKeyUrl: "https://console.mistral.ai/api-keys/", apiKeyHint: "Create a key under API Keys in the Mistral Console." },
12359
- { label: "Groq", url: "https://api.groq.com/openai/v1", apiKeyUrl: "https://console.groq.com/keys", apiKeyHint: "Create a key under API Keys in the Groq Console." },
12360
- { label: "DeepSeek", url: "https://api.deepseek.com/v1", apiKeyUrl: "https://platform.deepseek.com/api_keys", apiKeyHint: "Create a key under API Keys in the DeepSeek platform." },
12361
- { label: "Together AI", url: "https://api.together.xyz/v1", apiKeyUrl: "https://api.together.ai/settings/api-keys", apiKeyHint: "Create a key under Settings \u2192 API Keys in Together AI." },
12362
- { label: "OpenRouter", url: "https://openrouter.ai/api/v1", apiKeyUrl: "https://openrouter.ai/keys", apiKeyHint: "Create a key under Keys in your OpenRouter dashboard." },
12363
- { label: "Ollama (localhost)", url: "http://localhost:11434/v1", apiKeyHint: "Local Ollama does not require an API key \u2014 any non-empty value works." },
12364
- { label: "LM Studio (localhost)", url: "http://localhost:1234/v1", apiKeyHint: "Local LM Studio does not require an API key \u2014 any non-empty value works." },
12365
- { label: CUSTOM_PRESET, url: "" }
12366
- ];
12367
- var PROVIDER_DOMAINS = {
12368
- "Shuffle AI": "shuffler.io",
12369
- OpenAI: "openai.com",
12370
- Anthropic: "anthropic.com",
12371
- "Google Gemini": "gemini.google.com",
12372
- Mistral: "mistral.ai",
12373
- Groq: "groq.com",
12374
- DeepSeek: "deepseek.com",
12375
- "Together AI": "together.ai",
12376
- OpenRouter: "openrouter.ai",
12377
- "Ollama (localhost)": "ollama.com",
12378
- "LM Studio (localhost)": "lmstudio.ai"
12572
+ var CUSTOM_MODEL = "Custom\u2026";
12573
+ var PROVIDER_MODELS = {
12574
+ OpenAI: ["gpt-5.5", "gpt-5.5-pro", "gpt-5.4", "gpt-5.4-pro", "gpt-5.4-mini", "gpt-5.4-nano", "gpt-5.2", "gpt-5", "gpt-5-mini", "gpt-5-nano", "gpt-4.1", "o4-mini"],
12575
+ Anthropic: ["claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5", "claude-opus-4", "claude-sonnet-4", "claude-3-7-sonnet-latest"],
12576
+ "Google Gemini": ["gemini-3-pro-preview", "gemini-3-flash-preview", "gemini-3.1-pro-preview", "gemini-3.1-flash-lite-preview", "gemini-3.5-flash", "gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-flash-lite"],
12577
+ Mistral: ["mistral-large-2026", "mistral-medium-3", "mistral-small-3.2", "codestral-2026", "magistral-medium-2026", "ministral-8b-latest"],
12578
+ Groq: ["llama-4-maverick-17b-128e", "llama-4-scout-17b-16e", "llama-3.3-70b-versatile", "deepseek-r1-distill-llama-70b", "qwen-3-32b", "kimi-k2-instruct"],
12579
+ DeepSeek: ["deepseek-v3.5", "deepseek-v3", "deepseek-r1", "deepseek-coder-v3"],
12580
+ "Together AI": ["meta-llama/Llama-4-Maverick-17B-128E-Instruct", "meta-llama/Llama-4-Scout-17B-16E-Instruct", "deepseek-ai/DeepSeek-V3", "deepseek-ai/DeepSeek-R1", "Qwen/Qwen3-235B-A22B"],
12581
+ OpenRouter: ["openai/gpt-5.5", "openai/gpt-5.4", "anthropic/claude-opus-4.5", "anthropic/claude-sonnet-4.5", "google/gemini-3-pro-preview", "google/gemini-3-flash-preview", "meta-llama/llama-4-maverick", "deepseek/deepseek-v3.5", "x-ai/grok-4"],
12582
+ "Ollama (localhost)": ["llama3.3", "llama3.2", "qwen3", "qwen3:32b", "deepseek-r1", "deepseek-r1:70b", "mistral-small3", "phi4", "gemma3"],
12583
+ "LM Studio (localhost)": ["llama-3.3-70b-instruct", "qwen3-32b", "deepseek-r1-distill-qwen-32b", "mistral-small-3", "phi-4", "gemma-3-27b"]
12379
12584
  };
12380
12585
  var ProviderLogo = ({ label, url }) => {
12381
12586
  const [errored, setErrored] = useState13(false);
@@ -12405,46 +12610,16 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
12405
12610
  status: "pending",
12406
12611
  credentials: {}
12407
12612
  };
12408
- const currentUrl = authState.credentials?.url || "";
12409
- const attemptedDeletionRef = useRef9(/* @__PURE__ */ new Set());
12410
- useEffect12(() => {
12411
- if (authState.status === "testing") return;
12412
- const failedEntries = openaiEntries.filter((e) => e.validation && e.validation.valid === false && e.id);
12413
- if (failedEntries.length === 0) return;
12414
- let cancelled = false;
12415
- (async () => {
12416
- let deletedAny = false;
12417
- for (const entry of failedEntries) {
12418
- const id = entry.id;
12419
- if (attemptedDeletionRef.current.has(id)) continue;
12420
- attemptedDeletionRef.current.add(id);
12421
- try {
12422
- const resp = await fetch(getApiUrl(`/api/v1/apps/authentication/${id}`), {
12423
- method: "DELETE",
12424
- credentials: "include",
12425
- headers: { ...getAuthHeader() }
12426
- });
12427
- if (resp.ok) deletedAny = true;
12428
- } catch (err) {
12429
- console.error("[LocalLLMConfig] Failed to auto-delete failed OpenAI auth:", err);
12430
- }
12431
- }
12432
- if (!cancelled && deletedAny) {
12433
- await refreshAuth();
12434
- refreshAllIntegrationStatus();
12435
- }
12436
- })();
12437
- return () => {
12438
- cancelled = true;
12439
- };
12440
- }, [openaiEntries, authState.status, refreshAuth]);
12613
+ const savedUrlFromEntry = (openaiEntries[0]?.fields || []).find((f) => (f?.key || "").toLowerCase() === "url")?.value || "";
12614
+ const currentUrl = (authState.credentials?.url || savedUrlFromEntry || "").trim();
12615
+ const [customModel, setCustomModel] = useState13("");
12616
+ const [customMode, setCustomMode] = useState13(false);
12441
12617
  const hasOpenAIEntries = openaiEntries.length > 0;
12442
12618
  const effectivePreset = useMemo7(() => {
12443
12619
  if (selectedPreset) return selectedPreset;
12444
12620
  if (!currentUrl && !hasOpenAIEntries) return SHUFFLE_AI_PRESET;
12445
12621
  if (!currentUrl) return "";
12446
- const match = ENDPOINT_PRESETS.find((p) => p.url && p.url === currentUrl);
12447
- return match ? match.label : CUSTOM_PRESET;
12622
+ return detectLLMProvider(currentUrl)?.label || CUSTOM_PRESET;
12448
12623
  }, [selectedPreset, currentUrl, hasOpenAIEntries]);
12449
12624
  const applyShuffleAI = async () => {
12450
12625
  let deletedAny = false;
@@ -12481,7 +12656,16 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
12481
12656
  setSelectedPreset(label);
12482
12657
  const preset = ENDPOINT_PRESETS.find((p) => p.label === label);
12483
12658
  if (!preset) return;
12484
- handleAuthChange(OPENAI_APP_ID, { ...authState.credentials, url: preset.label === CUSTOM_PRESET ? customUrl : preset.url });
12659
+ const topModel = PROVIDER_MODELS[label]?.[0] || "";
12660
+ const existingModel = authState.credentials?.model || "";
12661
+ const nextModel = topModel || existingModel;
12662
+ setCustomMode(false);
12663
+ setCustomModel("");
12664
+ handleAuthChange(OPENAI_APP_ID, {
12665
+ ...authState.credentials,
12666
+ url: preset.label === CUSTOM_PRESET ? customUrl : preset.url,
12667
+ ...nextModel ? { model: nextModel } : {}
12668
+ });
12485
12669
  };
12486
12670
  const handleCustomUrlChange = (value) => {
12487
12671
  setCustomUrl(value);
@@ -12556,7 +12740,7 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
12556
12740
  );
12557
12741
  },
12558
12742
  slotProps: {
12559
- paper: { sx: { bgcolor: "hsl(var(--popover))", color: "hsl(var(--popover-foreground))", border: "1px solid hsl(var(--border))" } },
12743
+ paper: { sx: { bgcolor: "hsl(var(--popover))", color: "hsl(var(--popover-foreground))", border: "1px solid hsl(var(--border))", minWidth: 580 } },
12560
12744
  popper: { sx: { zIndex: 9999 } }
12561
12745
  }
12562
12746
  }
@@ -12619,6 +12803,59 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
12619
12803
  hideDocsLink: true,
12620
12804
  hideUrlFields: true,
12621
12805
  borderless: true,
12806
+ compactAuthForm: true,
12807
+ extraFieldsSlot: (PROVIDER_MODELS[effectivePreset]?.length ?? 0) > 0 ? ({ credentials, setField }) => {
12808
+ const liveModel = credentials.model || "";
12809
+ const presetModels = PROVIDER_MODELS[effectivePreset] || [];
12810
+ const liveIsCustom = liveModel !== "" && !presetModels.includes(liveModel);
12811
+ const showCustom = customMode || liveIsCustom;
12812
+ const liveSelectValue = showCustom ? CUSTOM_MODEL : liveModel || null;
12813
+ return /* @__PURE__ */ jsxs19(Box16, { sx: { display: "flex", flexDirection: "column", gap: 1 }, children: [
12814
+ /* @__PURE__ */ jsx22(Typography15, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: "Model" }),
12815
+ /* @__PURE__ */ jsx22(
12816
+ Autocomplete3,
12817
+ {
12818
+ size: "small",
12819
+ fullWidth: true,
12820
+ disableClearable: true,
12821
+ options: [...presetModels, CUSTOM_MODEL],
12822
+ value: liveSelectValue,
12823
+ onChange: (_e, val) => {
12824
+ if (!val) return;
12825
+ if (val === CUSTOM_MODEL) {
12826
+ setCustomMode(true);
12827
+ setField("model", customModel);
12828
+ } else {
12829
+ setCustomMode(false);
12830
+ setCustomModel("");
12831
+ setField("model", val);
12832
+ }
12833
+ },
12834
+ isOptionEqualToValue: (opt, val) => opt === val,
12835
+ slotProps: {
12836
+ paper: { sx: { bgcolor: "hsl(var(--popover))", color: "hsl(var(--popover-foreground))", border: "1px solid hsl(var(--border))" } },
12837
+ popper: { sx: { zIndex: 9999 } }
12838
+ },
12839
+ renderInput: (params) => /* @__PURE__ */ jsx22(TextField6, { ...params, placeholder: "Select a model\u2026" })
12840
+ }
12841
+ ),
12842
+ showCustom && /* @__PURE__ */ jsx22(
12843
+ TextField6,
12844
+ {
12845
+ size: "small",
12846
+ fullWidth: true,
12847
+ placeholder: "Enter a custom model identifier",
12848
+ value: customModel || (liveIsCustom ? liveModel : ""),
12849
+ onChange: (e) => {
12850
+ setCustomModel(e.target.value);
12851
+ setField("model", e.target.value);
12852
+ },
12853
+ helperText: "Exact model name as expected by the provider's API",
12854
+ sx: { "& .MuiFormHelperText-root": { color: "hsl(var(--muted-foreground))" } }
12855
+ }
12856
+ )
12857
+ ] });
12858
+ } : void 0,
12622
12859
  globalUrl,
12623
12860
  userdata,
12624
12861
  isLoaded,
@@ -12696,9 +12933,16 @@ var AgentRunDrawer = ({
12696
12933
  setActiveTab("localLLM");
12697
12934
  }
12698
12935
  };
12936
+ const onClose2 = () => {
12937
+ onClose();
12938
+ };
12699
12939
  window.addEventListener("agent-drawer-open", onOpen);
12700
- return () => window.removeEventListener("agent-drawer-open", onOpen);
12701
- }, []);
12940
+ window.addEventListener("agent-drawer-close", onClose2);
12941
+ return () => {
12942
+ window.removeEventListener("agent-drawer-open", onOpen);
12943
+ window.removeEventListener("agent-drawer-close", onClose2);
12944
+ };
12945
+ }, [onClose]);
12702
12946
  const effectiveLocalLLMSlot = localLLMSlot ?? /* @__PURE__ */ jsx23(
12703
12947
  LocalLLMConfig_default,
12704
12948
  {
@@ -12891,11 +13135,13 @@ import {
12891
13135
  AlertCircle,
12892
13136
  CheckCircle,
12893
13137
  Clock,
13138
+ Database,
12894
13139
  FileText,
12895
13140
  GitBranch,
12896
13141
  Globe,
13142
+ Hand,
12897
13143
  Loader2,
12898
- Server as Server2,
13144
+ Workflow as WorkflowIcon,
12899
13145
  XCircle,
12900
13146
  Zap,
12901
13147
  Search as SearchIcon2
@@ -13197,7 +13443,7 @@ var STATUS_CONFIG = {
13197
13443
  EXECUTING: { icon: /* @__PURE__ */ jsx24(Loader2, { size: 16 }), color: "hsl(var(--severity-medium, 38 92% 50%))", label: "Running" },
13198
13444
  RUNNING: { icon: /* @__PURE__ */ jsx24(Loader2, { size: 16 }), color: "hsl(var(--severity-medium, 38 92% 50%))", label: "Running" },
13199
13445
  WAITING: { icon: /* @__PURE__ */ jsx24(Clock, { size: 16 }), color: "hsl(var(--severity-info, 217 91% 60%))", label: "Waiting" },
13200
- LIMIT_REACHED: { icon: /* @__PURE__ */ jsx24(AlertTriangle2, { size: 16 }), color: "hsl(var(--severity-medium, 38 92% 50%))", label: "Limit reached" }
13446
+ LIMIT_REACHED: { icon: /* @__PURE__ */ jsx24(AlertTriangle2, { size: 16 }), color: "hsl(var(--severity-critical, 0 72% 55%))", label: "Limit reached" }
13201
13447
  };
13202
13448
  var getEffectiveStatus = (run) => {
13203
13449
  const raw = (run.status || "").toUpperCase();
@@ -13210,21 +13456,126 @@ var getEffectiveStatus = (run) => {
13210
13456
  }
13211
13457
  return raw;
13212
13458
  };
13213
- var getRunIcon = (run) => {
13214
- const src = (run.execution_source || "").toLowerCase();
13215
- const arg = (run.execution_argument || "").toLowerCase();
13216
- if (src.includes("schedule") || src.includes("cron")) return /* @__PURE__ */ jsx24(Clock, { size: 18 });
13217
- if (src.includes("webhook") || src.includes("http")) return /* @__PURE__ */ jsx24(Globe, { size: 18 });
13218
- if (arg.includes("alert") || arg.includes("detect")) return /* @__PURE__ */ jsx24(Activity, { size: 18 });
13219
- if (arg.includes("report") || arg.includes("email")) return /* @__PURE__ */ jsx24(FileText, { size: 18 });
13220
- if (arg.includes("endpoint") || arg.includes("server")) return /* @__PURE__ */ jsx24(Server2, { size: 18 });
13221
- return /* @__PURE__ */ jsx24(Zap, { size: 18 });
13459
+ var SOURCE_ICON_SIZE = 18;
13460
+ var looksLikeExecutionId = (s) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s.trim());
13461
+ var DATASTORE_KEY_RE = /\bKey:\s*(\S+)/i;
13462
+ var DATASTORE_CATEGORY_RE = /\bCategory:\s*(\S+)/i;
13463
+ var parseDatastoreTask = (arg) => {
13464
+ if (!arg) return null;
13465
+ const k = arg.match(DATASTORE_KEY_RE);
13466
+ const c = arg.match(DATASTORE_CATEGORY_RE);
13467
+ if (!k || !c) return null;
13468
+ const key = (k[1] || "").trim();
13469
+ const category = (c[1] || "").trim();
13470
+ if (!key || !category) return null;
13471
+ return { key, category };
13472
+ };
13473
+ var isAIAgentResult = (result) => String(result?.action?.app_name || "").trim().toLowerCase() === "ai agent";
13474
+ var getAIAgentResultPayload = (run) => {
13475
+ const results = Array.isArray(run.results) ? run.results : [];
13476
+ const agentResult = results.find(isAIAgentResult);
13477
+ if (!agentResult || typeof agentResult !== "object" || !("result" in agentResult)) return null;
13478
+ return tryParseJson(agentResult.result);
13479
+ };
13480
+ var getDirectAgentInput = (payload) => {
13481
+ if (!payload || typeof payload !== "object") return null;
13482
+ const obj = payload;
13483
+ if (typeof obj.original_input === "string" && obj.original_input.trim()) {
13484
+ return obj.original_input.trim();
13485
+ }
13486
+ if (typeof obj.input === "string" && obj.input.trim()) {
13487
+ return obj.input.trim();
13488
+ }
13489
+ return null;
13490
+ };
13491
+ var findDatastoreTaskInRun = (run) => {
13492
+ const agentInput = getDirectAgentInput(getAIAgentResultPayload(run));
13493
+ const agentHit = parseDatastoreTask(agentInput || void 0);
13494
+ if (agentHit) return agentHit;
13495
+ const anyRun = run;
13496
+ const candidates = [];
13497
+ if (typeof anyRun.original_input === "string") candidates.push(anyRun.original_input);
13498
+ if (typeof anyRun.input === "string") candidates.push(anyRun.input);
13499
+ if (run.execution_argument) candidates.push(run.execution_argument);
13500
+ if (run.result) candidates.push(run.result);
13501
+ if (Array.isArray(anyRun.results)) {
13502
+ try {
13503
+ candidates.push(JSON.stringify(anyRun.results));
13504
+ } catch {
13505
+ }
13506
+ }
13507
+ for (const c of candidates) {
13508
+ const hit = parseDatastoreTask(c);
13509
+ if (hit) return hit;
13510
+ }
13511
+ return null;
13512
+ };
13513
+ var classifyRunSource = (run) => {
13514
+ const raw = (run.execution_source || "").trim();
13515
+ const src = raw.toLowerCase();
13516
+ const ds = findDatastoreTaskInRun(run);
13517
+ if (ds || src.includes("datastore") || src.includes("enrichment") || src.includes("automation")) {
13518
+ return {
13519
+ kind: "datastore",
13520
+ label: "Datastore automation",
13521
+ reason: ds ? `Started by datastore automation (category "${ds.category}", key "${ds.key}"). Click to open in Datastore.` : "Started by a datastore automation (e.g. enrichment trigger).",
13522
+ icon: /* @__PURE__ */ jsx24(Database, { size: SOURCE_ICON_SIZE }),
13523
+ datastoreKey: ds?.key,
13524
+ datastoreCategory: ds?.category
13525
+ };
13526
+ }
13527
+ if (src.includes("schedule") || src.includes("cron")) {
13528
+ return {
13529
+ kind: "schedule",
13530
+ label: "Schedule",
13531
+ reason: "Started by a scheduled trigger (cron).",
13532
+ icon: /* @__PURE__ */ jsx24(Clock, { size: SOURCE_ICON_SIZE })
13533
+ };
13534
+ }
13535
+ if (src.includes("webhook") || src.includes("http")) {
13536
+ return {
13537
+ kind: "webhook",
13538
+ label: "Webhook",
13539
+ reason: "Started by an incoming webhook / HTTP trigger.",
13540
+ icon: /* @__PURE__ */ jsx24(Globe, { size: SOURCE_ICON_SIZE })
13541
+ };
13542
+ }
13543
+ if (src.includes("form")) {
13544
+ return {
13545
+ kind: "form",
13546
+ label: "Form",
13547
+ reason: "Started by a form submission.",
13548
+ icon: /* @__PURE__ */ jsx24(FileText, { size: SOURCE_ICON_SIZE })
13549
+ };
13550
+ }
13551
+ if (raw && looksLikeExecutionId(raw)) {
13552
+ return {
13553
+ kind: "workflow",
13554
+ label: "Workflow",
13555
+ reason: "Started by another workflow as a subflow.",
13556
+ icon: /* @__PURE__ */ jsx24(WorkflowIcon, { size: SOURCE_ICON_SIZE })
13557
+ };
13558
+ }
13559
+ if (src === "" || src === "manual" || src === "default" || src === "demo") {
13560
+ return {
13561
+ kind: "manual",
13562
+ label: "Manual",
13563
+ reason: "Started manually from the Agents UI.",
13564
+ icon: /* @__PURE__ */ jsx24(Hand, { size: SOURCE_ICON_SIZE })
13565
+ };
13566
+ }
13567
+ return {
13568
+ kind: "unknown",
13569
+ label: raw || "Unknown",
13570
+ reason: raw ? `Started by "${raw}".` : "Trigger source unknown.",
13571
+ icon: /* @__PURE__ */ jsx24(Zap, { size: SOURCE_ICON_SIZE })
13572
+ };
13222
13573
  };
13223
13574
  var getRunIconColor = (run) => {
13224
13575
  const status = getEffectiveStatus(run);
13225
13576
  if (status === "FINISHED" || status === "SUCCESS") return "hsl(var(--severity-low, 142 71% 45%))";
13226
13577
  if (status === "FAILED" || status === "ABORTED") return "hsl(var(--severity-critical, 0 72% 55%))";
13227
- if (status === "LIMIT_REACHED") return "hsl(var(--severity-medium, 38 92% 50%))";
13578
+ if (status === "LIMIT_REACHED") return "hsl(var(--severity-critical, 0 72% 55%))";
13228
13579
  if (status === "EXECUTING" || status === "RUNNING") return "hsl(var(--severity-medium, 38 92% 50%))";
13229
13580
  return "hsl(var(--primary, 24 100% 50%))";
13230
13581
  };
@@ -13322,9 +13673,12 @@ var tryParseJson = (s) => {
13322
13673
  }
13323
13674
  };
13324
13675
  var getRunPrompt = (run) => {
13325
- const results = Array.isArray(run.results) ? run.results : null;
13676
+ const anyRun = run;
13677
+ const agentInput = getDirectAgentInput(getAIAgentResultPayload(run));
13678
+ if (agentInput) return agentInput;
13679
+ const results = Array.isArray(anyRun.results) ? anyRun.results : null;
13326
13680
  if (results) {
13327
- const agentResult = results.find((r) => r?.action?.app_name === "AI Agent");
13681
+ const agentResult = results.find(isAIAgentResult);
13328
13682
  if (agentResult?.result) {
13329
13683
  const hit = deepFindPrompt(tryParseJson(agentResult.result));
13330
13684
  if (hit) return hit;
@@ -13335,6 +13689,12 @@ var getRunPrompt = (run) => {
13335
13689
  if (hit) return hit;
13336
13690
  }
13337
13691
  }
13692
+ if (typeof anyRun.original_input === "string" && anyRun.original_input.trim()) {
13693
+ return anyRun.original_input.trim();
13694
+ }
13695
+ if (typeof anyRun.input === "string" && anyRun.input.trim()) {
13696
+ return anyRun.input.trim();
13697
+ }
13338
13698
  if (run.result) {
13339
13699
  const hit = deepFindPrompt(tryParseJson(run.result));
13340
13700
  if (hit) return hit;
@@ -13375,7 +13735,9 @@ var getRunSubtitle = (run) => {
13375
13735
  if (run.result.length < 120) return run.result;
13376
13736
  }
13377
13737
  }
13378
- return run.execution_source || "Agent execution";
13738
+ const status = getEffectiveStatus(run);
13739
+ const isRunning = status === "EXECUTING" || status === "RUNNING" || status === "WAITING";
13740
+ return run.execution_source || (isRunning ? "Agent still running\u2026" : "Agent execution");
13379
13741
  };
13380
13742
  var normalizeResultStatus = (s) => {
13381
13743
  const v = (s || "").toUpperCase();
@@ -13477,41 +13839,60 @@ var AgentRunRow = ({ run, onClick, sx, appIcons, onAppClick }) => {
13477
13839
  ...Array.isArray(sx) ? sx : sx ? [sx] : []
13478
13840
  ],
13479
13841
  children: [
13480
- /* @__PURE__ */ jsx24(
13481
- Box18,
13482
- {
13483
- sx: {
13484
- width: 40,
13485
- height: 40,
13486
- borderRadius: "50%",
13487
- display: "flex",
13488
- alignItems: "center",
13489
- justifyContent: "center",
13490
- bgcolor: `${iconColor}15`,
13491
- color: iconColor,
13492
- flexShrink: 0
13493
- },
13494
- children: getRunIcon(run)
13495
- }
13496
- ),
13842
+ (() => {
13843
+ const sourceInfo = classifyRunSource(run);
13844
+ const dsLink = sourceInfo.kind === "datastore" && sourceInfo.datastoreKey && sourceInfo.datastoreCategory ? `https://shuffler.io/admin?tab=datastore&category=${encodeURIComponent(sourceInfo.datastoreCategory)}&key=${encodeURIComponent(sourceInfo.datastoreKey)}` : null;
13845
+ return /* @__PURE__ */ jsx24(
13846
+ Tooltip12,
13847
+ {
13848
+ title: /* @__PURE__ */ jsxs21(Box18, { sx: { lineHeight: 1.4 }, children: [
13849
+ /* @__PURE__ */ jsx24(Box18, { sx: { fontWeight: 600 }, children: sourceInfo.label }),
13850
+ /* @__PURE__ */ jsx24(Box18, { sx: { opacity: 0.85 }, children: sourceInfo.reason })
13851
+ ] }),
13852
+ placement: "top",
13853
+ arrow: true,
13854
+ children: /* @__PURE__ */ jsx24(
13855
+ Box18,
13856
+ {
13857
+ onClick: dsLink ? (e) => {
13858
+ e.stopPropagation();
13859
+ window.open(dsLink, "_blank", "noopener,noreferrer");
13860
+ } : void 0,
13861
+ sx: {
13862
+ width: 40,
13863
+ height: 40,
13864
+ borderRadius: "50%",
13865
+ display: "flex",
13866
+ alignItems: "center",
13867
+ justifyContent: "center",
13868
+ bgcolor: `${iconColor}15`,
13869
+ color: iconColor,
13870
+ flexShrink: 0,
13871
+ cursor: dsLink ? "pointer" : "inherit",
13872
+ transition: "background 0.15s ease",
13873
+ "&:hover": dsLink ? { bgcolor: `${iconColor}30` } : void 0
13874
+ },
13875
+ children: sourceInfo.icon
13876
+ }
13877
+ )
13878
+ }
13879
+ );
13880
+ })(),
13497
13881
  /* @__PURE__ */ jsxs21(Box18, { sx: { flex: 1, minWidth: 0 }, children: [
13498
- /* @__PURE__ */ jsxs21(Box18, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 0.25 }, children: [
13499
- /* @__PURE__ */ jsx24(
13500
- Typography17,
13501
- {
13502
- sx: {
13503
- fontSize: "0.9rem",
13504
- fontWeight: 500,
13505
- color: "hsl(var(--foreground))",
13506
- overflow: "hidden",
13507
- textOverflow: "ellipsis",
13508
- whiteSpace: "nowrap"
13509
- },
13510
- children: getRunTitle(run)
13511
- }
13512
- ),
13513
- /* @__PURE__ */ jsx24(Box18, { sx: { display: "flex", alignItems: "center", color: cfg.color, flexShrink: 0 }, children: cfg.icon })
13514
- ] }),
13882
+ /* @__PURE__ */ jsx24(Box18, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 0.25 }, children: /* @__PURE__ */ jsx24(
13883
+ Typography17,
13884
+ {
13885
+ sx: {
13886
+ fontSize: "0.9rem",
13887
+ fontWeight: 500,
13888
+ color: "hsl(var(--foreground))",
13889
+ overflow: "hidden",
13890
+ textOverflow: "ellipsis",
13891
+ whiteSpace: "nowrap"
13892
+ },
13893
+ children: getRunTitle(run)
13894
+ }
13895
+ ) }),
13515
13896
  /* @__PURE__ */ jsx24(
13516
13897
  Typography17,
13517
13898
  {
@@ -13606,18 +13987,7 @@ var AgentRunRow = ({ run, onClick, sx, appIcons, onAppClick }) => {
13606
13987
  ) }, t.name);
13607
13988
  })
13608
13989
  }
13609
- ) : /* @__PURE__ */ jsx24(
13610
- Typography17,
13611
- {
13612
- sx: {
13613
- fontSize: "0.7rem",
13614
- color: "hsl(var(--muted-foreground))",
13615
- opacity: 0.5,
13616
- fontStyle: "italic"
13617
- },
13618
- children: "No apps"
13619
- }
13620
- )
13990
+ ) : null
13621
13991
  }
13622
13992
  )
13623
13993
  ]
@@ -14440,6 +14810,15 @@ var AgentsView = ({
14440
14810
  open: false,
14441
14811
  tab: "localLLM"
14442
14812
  });
14813
+ useEffect15(() => {
14814
+ if (typeof window === "undefined") return;
14815
+ const handler = (e) => {
14816
+ const detail = e.detail;
14817
+ setBuiltInDrawer({ open: true, tab: detail?.tab ?? "localLLM" });
14818
+ };
14819
+ window.addEventListener("agent-drawer-open", handler);
14820
+ return () => window.removeEventListener("agent-drawer-open", handler);
14821
+ }, []);
14443
14822
  const effectiveSchedule = useCallback10(
14444
14823
  async (info) => {
14445
14824
  if (onSchedule) return onSchedule(info);