@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.js CHANGED
@@ -2464,6 +2464,8 @@ var AppAuthCard = ({
2464
2464
  hideDocsLink,
2465
2465
  hideUrlFields,
2466
2466
  borderless,
2467
+ compactAuthForm,
2468
+ extraFieldsSlot,
2467
2469
  globalUrl,
2468
2470
  userdata,
2469
2471
  isLoaded,
@@ -2530,10 +2532,6 @@ var AppAuthCard = ({
2530
2532
  if (!alreadyValid && newestId !== autoTestFiredRef.current) {
2531
2533
  autoTestFiredRef.current = newestId;
2532
2534
  setTimeout(() => {
2533
- toast({
2534
- title: "Auto-testing new authentication",
2535
- description: `Verifying connection for ${app.name.replace(/_/g, " ")}...`
2536
- });
2537
2535
  setTestingAuthId(newestId);
2538
2536
  onTestConnection(app.objectID, newestId);
2539
2537
  }, 500);
@@ -2595,11 +2593,17 @@ var AppAuthCard = ({
2595
2593
  executionId: authState.executionId,
2596
2594
  errorCode: authState.errorCode
2597
2595
  });
2596
+ if (autoTestFiredRef.current === testingAuthId) {
2597
+ setSelectedAuthId(ADD_NEW_AUTH);
2598
+ setUserHasSelected(true);
2599
+ setPendingFailedAuthId(testingAuthId);
2600
+ autoTestFiredRef.current = null;
2601
+ }
2598
2602
  setTestingAuthId(null);
2599
2603
  }
2600
2604
  }, [authState.status, authState.errorMessage, authState.successMessage, authState.warningMessage, testingAuthId, apiAuthEntries, wasPreValidatedPerAuth]);
2601
2605
  const isCredentialError = localTestMessages.errorCode === 401 || localTestMessages.errorCode === 403;
2602
- const showAddNewForm = selectedAuthId === ADD_NEW_AUTH;
2606
+ const showAddNewForm = compactAuthForm ? true : selectedAuthId === ADD_NEW_AUTH;
2603
2607
  const isConfigured = selectedAuth?.active === true;
2604
2608
  const isTested = selectedAuth?.validation?.valid === true;
2605
2609
  const getLastValidTimestamp = () => {
@@ -2621,6 +2625,8 @@ var AppAuthCard = ({
2621
2625
  });
2622
2626
  };
2623
2627
  const [localCredentials, setLocalCredentials] = (0, import_react7.useState)(authState.credentials || {});
2628
+ const [revealedFields, setRevealedFields] = (0, import_react7.useState)({});
2629
+ const [pendingFailedAuthId, setPendingFailedAuthId] = (0, import_react7.useState)(null);
2624
2630
  const [fieldErrors, setFieldErrors] = (0, import_react7.useState)({});
2625
2631
  const [loading, setLoading] = (0, import_react7.useState)(false);
2626
2632
  const [saving, setSaving] = (0, import_react7.useState)(false);
@@ -2696,7 +2702,8 @@ var AppAuthCard = ({
2696
2702
  for (const [k, v] of Object.entries(incoming)) {
2697
2703
  const lk = k.toLowerCase();
2698
2704
  const isUrlish = lk.includes("url") || lk.includes("endpoint") || lk.includes("host");
2699
- if (isUrlish && typeof v === "string" && v !== prev[k]) {
2705
+ const isModel = lk === "model";
2706
+ if ((isUrlish || isModel) && typeof v === "string" && v !== prev[k]) {
2700
2707
  next[k] = v;
2701
2708
  changed = true;
2702
2709
  }
@@ -2892,7 +2899,7 @@ var AppAuthCard = ({
2892
2899
  sx: {
2893
2900
  "& .MuiOutlinedInput-root": {
2894
2901
  backgroundColor: "hsl(var(--background))",
2895
- borderRadius: 2,
2902
+ borderRadius: 1,
2896
2903
  "& fieldset": { borderColor: "hsl(var(--border))" },
2897
2904
  "&:hover fieldset": { borderColor: "hsl(var(--border) / 0.8)" },
2898
2905
  "&.Mui-focused fieldset": { borderColor: "hsl(var(--primary))" }
@@ -2915,7 +2922,7 @@ var AppAuthCard = ({
2915
2922
  sx: {
2916
2923
  "& .MuiOutlinedInput-root": {
2917
2924
  backgroundColor: "hsl(var(--background))",
2918
- borderRadius: 2,
2925
+ borderRadius: 1,
2919
2926
  "& fieldset": { borderColor: "hsl(var(--border))" },
2920
2927
  "&:hover fieldset": { borderColor: "hsl(var(--border) / 0.8)" },
2921
2928
  "&.Mui-focused fieldset": { borderColor: "hsl(var(--primary))" }
@@ -2940,7 +2947,7 @@ var AppAuthCard = ({
2940
2947
  displayEmpty: true,
2941
2948
  sx: {
2942
2949
  backgroundColor: "action.hover",
2943
- borderRadius: 2,
2950
+ borderRadius: 1,
2944
2951
  color: "text.primary",
2945
2952
  "& .MuiOutlinedInput-notchedOutline": { borderColor: "divider" },
2946
2953
  "&:hover .MuiOutlinedInput-notchedOutline": { borderColor: "text.disabled" },
@@ -2985,6 +2992,7 @@ var AppAuthCard = ({
2985
2992
  const fieldKey = param.id || param.name || `param_${index}`;
2986
2993
  const lowerName = (param.name || "").toLowerCase();
2987
2994
  const isSecretField = lowerName.includes("password") || lowerName.includes("secret") || lowerName.includes("key") || lowerName.includes("token");
2995
+ const isRevealed = !!revealedFields[fieldKey];
2988
2996
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2989
2997
  import_material4.TextField,
2990
2998
  {
@@ -3015,13 +3023,25 @@ var AppAuthCard = ({
3015
3023
  onFocus: (e) => {
3016
3024
  e.target.removeAttribute("readonly");
3017
3025
  }
3018
- }
3026
+ },
3027
+ input: isSecretField ? {
3028
+ endAdornment: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3029
+ import_material4.IconButton,
3030
+ {
3031
+ size: "small",
3032
+ onClick: () => setRevealedFields((prev) => ({ ...prev, [fieldKey]: !prev[fieldKey] })),
3033
+ "aria-label": isRevealed ? `Hide ${param.name}` : `Show ${param.name}`,
3034
+ sx: { color: "hsl(var(--muted-foreground))", "&:hover": { color: "hsl(var(--foreground))" } },
3035
+ children: isRevealed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.EyeOff, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.Eye, { size: 16 })
3036
+ }
3037
+ )
3038
+ } : void 0
3019
3039
  },
3020
3040
  name: `auth-${fieldKey}-${app.objectID}-${Math.random().toString(36).slice(2, 8)}`,
3021
3041
  sx: {
3022
3042
  "& .MuiOutlinedInput-root": {
3023
3043
  backgroundColor: isSecretField ? "hsl(var(--primary) / 0.06)" : "hsl(var(--muted))",
3024
- borderRadius: 2,
3044
+ borderRadius: 1,
3025
3045
  "& fieldset": {
3026
3046
  borderColor: fieldErrors[fieldKey] ? "hsl(var(--destructive))" : isSecretField ? "hsl(var(--primary) / 0.5)" : "hsl(var(--border))",
3027
3047
  borderWidth: isSecretField ? 2 : 1
@@ -3033,7 +3053,7 @@ var AppAuthCard = ({
3033
3053
  },
3034
3054
  "& .MuiInputBase-input": {
3035
3055
  color: "hsl(var(--foreground))",
3036
- ...isSecretField && {
3056
+ ...isSecretField && !isRevealed && {
3037
3057
  WebkitTextSecurity: "disc",
3038
3058
  textSecurity: "disc",
3039
3059
  fontFamily: "text-security-disc, monospace"
@@ -3084,7 +3104,6 @@ var AppAuthCard = ({
3084
3104
  setSaveSuccess(success);
3085
3105
  if (success) {
3086
3106
  setUserHasSelected(false);
3087
- setLocalCredentials({});
3088
3107
  setFieldErrors({});
3089
3108
  }
3090
3109
  };
@@ -3292,7 +3311,7 @@ var AppAuthCard = ({
3292
3311
  borderTop: borderless ? "none" : "1px solid hsl(var(--border))"
3293
3312
  },
3294
3313
  children: [
3295
- apiAuthEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material4.Box, { sx: { mb: 3 }, children: [
3314
+ !compactAuthForm && apiAuthEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material4.Box, { sx: { mb: 3 }, children: [
3296
3315
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material4.Typography, { variant: "body2", sx: { color: "hsl(var(--muted-foreground))", mb: 1 }, children: "Select authentication" }),
3297
3316
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material4.FormControl, { fullWidth: true, size: "small", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3298
3317
  import_material4.Select,
@@ -3831,7 +3850,7 @@ var AppAuthCard = ({
3831
3850
  children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material4.Typography, { 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." })
3832
3851
  }
3833
3852
  ),
3834
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material4.Typography, { variant: "subtitle2", sx: { color: "hsl(var(--foreground))", fontWeight: 600, mb: 2 }, children: apiAuthEntries.length === 0 ? "Configure Authentication" : "Add New Authentication" }),
3853
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material4.Typography, { variant: "subtitle2", sx: { color: "hsl(var(--foreground))", fontWeight: 600, mb: 2 }, children: apiAuthEntries.length === 0 ? `Configure ${app.name.replace(/_/g, " ")}` : "Add New Authentication" }),
3835
3854
  loading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material4.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "center", py: 4 }, children: [
3836
3855
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material4.CircularProgress, { size: 32, sx: { color: "hsl(var(--primary))" } }),
3837
3856
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material4.Typography, { sx: { ml: 2, color: "hsl(var(--muted-foreground))" }, children: "Loading configuration..." })
@@ -3867,6 +3886,7 @@ var AppAuthCard = ({
3867
3886
  ] })
3868
3887
  }
3869
3888
  ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material4.Box, { sx: { display: "flex", flexDirection: "column", gap: 3 }, children: [
3889
+ extraFieldsSlot?.({ credentials: localCredentials, setField: handleCredentialChange }),
3870
3890
  renderOAuth2Fields(),
3871
3891
  renderParameterFields(),
3872
3892
  authState.status === "error" && authState.errorMessage && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
@@ -3921,38 +3941,97 @@ var AppAuthCard = ({
3921
3941
  children: "Failed to save authentication. Please try again."
3922
3942
  }
3923
3943
  ),
3924
- !isOAuth2 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material4.Box, { sx: { display: "flex", justifyContent: "flex-end", pt: 1.5 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3925
- import_material4.Button,
3926
- {
3927
- variant: "outlined",
3928
- size: "medium",
3929
- onClick: (e) => {
3930
- e.stopPropagation();
3931
- handleSave();
3932
- },
3933
- disabled: saving || !isFormValid(),
3934
- sx: {
3935
- borderColor: isFormValid() ? "hsl(var(--primary) / 0.5)" : "hsl(var(--border))",
3936
- color: isFormValid() ? "hsl(var(--primary))" : "hsl(var(--muted-foreground))",
3937
- fontWeight: 600,
3938
- textTransform: "none",
3939
- fontSize: "0.9rem",
3940
- px: 3,
3941
- py: 1,
3942
- borderRadius: 2,
3943
- transition: "all 0.2s ease",
3944
- "&:hover": {
3945
- borderColor: "hsl(var(--primary))",
3946
- backgroundColor: "hsl(var(--primary) / 0.08)"
3944
+ !isOAuth2 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material4.Box, { sx: { display: "flex", justifyContent: "flex-end", pt: 1.5, gap: 1, flexWrap: "wrap" }, children: [
3945
+ pendingFailedAuthId && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3946
+ import_material4.Button,
3947
+ {
3948
+ variant: "text",
3949
+ size: "medium",
3950
+ onClick: async (e) => {
3951
+ e.stopPropagation();
3952
+ const previousFailedId = pendingFailedAuthId;
3953
+ setPendingFailedAuthId(null);
3954
+ setUserHasSelected(true);
3955
+ setFieldErrors({});
3956
+ await onSaveAuth(app.objectID, localCredentials);
3957
+ let entries = apiAuthEntries;
3958
+ if (onRefreshAuth) {
3959
+ await onRefreshAuth();
3960
+ }
3961
+ entries = apiAuthEntries || [];
3962
+ const sorted = [...entries].sort((a, b) => (b.created || 0) - (a.created || 0));
3963
+ const acceptId = sorted[0]?.id || previousFailedId;
3964
+ setSelectedAuthId(acceptId);
3965
+ const stale = entries.filter((e2) => e2.id && e2.id !== acceptId);
3966
+ await Promise.all(stale.map(async (entry) => {
3967
+ try {
3968
+ await fetch(getApiUrl(`/api/v1/apps/authentication/${entry.id}`), {
3969
+ method: "DELETE",
3970
+ credentials: "include",
3971
+ headers: { ...getAuthHeader() }
3972
+ });
3973
+ } catch (err) {
3974
+ console.error("[AppAuthCard] Failed to delete stale auth on Save anyway:", err);
3975
+ }
3976
+ }));
3977
+ if (onRefreshAuth) await onRefreshAuth();
3978
+ if (onSelectAuth) onSelectAuth(app.objectID, acceptId);
3979
+ if (typeof window !== "undefined") {
3980
+ window.dispatchEvent(new CustomEvent("integrations-changed"));
3981
+ window.dispatchEvent(new CustomEvent("agent-drawer-close"));
3982
+ }
3947
3983
  },
3948
- "&.Mui-disabled": {
3949
- borderColor: "hsl(var(--border))",
3950
- color: "hsl(var(--muted-foreground))"
3951
- }
3952
- },
3953
- children: saving ? "Saving..." : "Save Authentication"
3954
- }
3955
- ) }),
3984
+ sx: {
3985
+ color: "hsl(var(--muted-foreground))",
3986
+ fontWeight: 600,
3987
+ textTransform: "none",
3988
+ fontSize: "0.85rem",
3989
+ px: 2,
3990
+ py: 1,
3991
+ borderRadius: 2,
3992
+ "&:hover": {
3993
+ color: "hsl(var(--foreground))",
3994
+ backgroundColor: "hsl(var(--muted) / 0.5)"
3995
+ }
3996
+ },
3997
+ title: "Our test isn't always authoritative \u2014 keep the credentials you saved and dismiss the failure.",
3998
+ children: "Save anyway"
3999
+ }
4000
+ ),
4001
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4002
+ import_material4.Button,
4003
+ {
4004
+ variant: "outlined",
4005
+ size: "medium",
4006
+ onClick: (e) => {
4007
+ e.stopPropagation();
4008
+ setPendingFailedAuthId(null);
4009
+ handleSave();
4010
+ },
4011
+ disabled: saving || !isFormValid(),
4012
+ sx: {
4013
+ borderColor: isFormValid() ? "hsl(var(--primary) / 0.5)" : "hsl(var(--border))",
4014
+ color: isFormValid() ? "hsl(var(--primary))" : "hsl(var(--muted-foreground))",
4015
+ fontWeight: 600,
4016
+ textTransform: "none",
4017
+ fontSize: "0.9rem",
4018
+ px: 3,
4019
+ py: 1,
4020
+ borderRadius: 2,
4021
+ transition: "all 0.2s ease",
4022
+ "&:hover": {
4023
+ borderColor: "hsl(var(--primary))",
4024
+ backgroundColor: "hsl(var(--primary) / 0.08)"
4025
+ },
4026
+ "&.Mui-disabled": {
4027
+ borderColor: "hsl(var(--border))",
4028
+ color: "hsl(var(--muted-foreground))"
4029
+ }
4030
+ },
4031
+ children: saving ? "Testing..." : pendingFailedAuthId ? "Retry Test" : "Test Authentication"
4032
+ }
4033
+ )
4034
+ ] }),
3956
4035
  isOAuth2 && (() => {
3957
4036
  const hasClientId = !!localCredentials["client_id"]?.trim();
3958
4037
  const hasClientSecret = !!localCredentials["client_secret"]?.trim();
@@ -6029,28 +6108,38 @@ function AppDetailDrawer({
6029
6108
  }
6030
6109
  }, [open, appName]);
6031
6110
  const isLoadingAll = appLoading || isAuthenticated && appAuthLoading;
6111
+ const drawerWidth = `min(${width}px, 100vw)`;
6032
6112
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
6033
6113
  import_material9.Drawer,
6034
6114
  {
6035
6115
  anchor,
6036
6116
  open,
6037
6117
  onClose: handleClose,
6038
- slotProps: {
6039
- paper: {
6040
- className: scopeClassName,
6041
- sx: {
6042
- width: { xs: "100%", sm: width },
6043
- maxWidth: "100vw",
6044
- display: "flex",
6045
- flexDirection: "column",
6046
- background: "linear-gradient(180deg, hsl(var(--card)) 0%, hsl(var(--background)) 100%)",
6047
- borderLeft: anchor === "right" ? "1px solid hsl(var(--border))" : "none",
6048
- borderRight: anchor === "left" ? "1px solid hsl(var(--border))" : "none"
6049
- }
6118
+ PaperProps: {
6119
+ className: scopeClassName,
6120
+ sx: {
6121
+ width: drawerWidth,
6122
+ minWidth: drawerWidth,
6123
+ maxWidth: drawerWidth,
6124
+ flex: `0 0 ${drawerWidth}`,
6125
+ height: "100vh",
6126
+ display: "flex",
6127
+ flexDirection: "column",
6128
+ overflow: "hidden",
6129
+ background: "linear-gradient(180deg, hsl(var(--card)) 0%, hsl(var(--background)) 100%)",
6130
+ borderLeft: anchor === "right" ? "1px solid hsl(var(--border))" : "none",
6131
+ borderRight: anchor === "left" ? "1px solid hsl(var(--border))" : "none"
6050
6132
  }
6051
6133
  },
6052
6134
  sx: {
6053
- "& .MuiDrawer-paper": { boxSizing: "border-box" }
6135
+ zIndex: 9999,
6136
+ "& .MuiDrawer-paper": {
6137
+ boxSizing: "border-box",
6138
+ width: `${drawerWidth} !important`,
6139
+ minWidth: `${drawerWidth} !important`,
6140
+ maxWidth: `${drawerWidth} !important`,
6141
+ flex: `0 0 ${drawerWidth} !important`
6142
+ }
6054
6143
  },
6055
6144
  children: [
6056
6145
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
@@ -7083,6 +7172,7 @@ function AppSearchDrawer({
7083
7172
  const t = setTimeout(() => setHighlightActive(true), highlightDelayMs);
7084
7173
  return () => clearTimeout(t);
7085
7174
  }, [open, highlightAppName, highlightDelayMs]);
7175
+ const drawerWidth = `min(${width}px, 100vw)`;
7086
7176
  const handleClose = () => {
7087
7177
  setDetailAppName(null);
7088
7178
  setDetailAppId(null);
@@ -7159,29 +7249,38 @@ function AppSearchDrawer({
7159
7249
  anchor,
7160
7250
  open: open && detailAppName === null,
7161
7251
  onClose: handleClose,
7162
- slotProps: {
7163
- paper: {
7164
- className: scopeClassName,
7165
- sx: {
7166
- // Strict, environment-independent sizing so the drawer
7167
- // looks identical on every host (Shuffle Security, /agents,
7168
- // test page, embedded library, etc.). No breakpoint variance.
7169
- width: `min(${width}px, 100vw)`,
7170
- minWidth: `min(${width}px, 100vw)`,
7171
- maxWidth: "100vw",
7172
- height: "100vh",
7173
- display: "flex",
7174
- flexDirection: "column",
7175
- overflow: "hidden",
7176
- background: "linear-gradient(180deg, hsl(var(--card)) 0%, hsl(var(--background)) 100%)",
7177
- borderLeft: anchor === "right" ? "1px solid hsl(var(--border))" : "none",
7178
- borderRight: anchor === "left" ? "1px solid hsl(var(--border))" : "none"
7179
- }
7252
+ PaperProps: {
7253
+ className: scopeClassName,
7254
+ sx: {
7255
+ // Strict, environment-independent sizing so the drawer
7256
+ // looks identical on every host (Shuffle Security, /agents,
7257
+ // test page, embedded library, etc.). No breakpoint variance.
7258
+ // NOTE: use PaperProps (not slotProps.paper) — slotProps.paper
7259
+ // was added in MUI v6 and is silently ignored on MUI v5 hosts,
7260
+ // which made the drawer collapse to content width when
7261
+ // consumed from the published library.
7262
+ width: drawerWidth,
7263
+ minWidth: drawerWidth,
7264
+ maxWidth: drawerWidth,
7265
+ flex: `0 0 ${drawerWidth}`,
7266
+ height: "100vh",
7267
+ display: "flex",
7268
+ flexDirection: "column",
7269
+ overflow: "hidden",
7270
+ background: "linear-gradient(180deg, hsl(var(--card)) 0%, hsl(var(--background)) 100%)",
7271
+ borderLeft: anchor === "right" ? "1px solid hsl(var(--border))" : "none",
7272
+ borderRight: anchor === "left" ? "1px solid hsl(var(--border))" : "none"
7180
7273
  }
7181
7274
  },
7182
7275
  sx: {
7183
7276
  zIndex: 9999,
7184
- "& .MuiDrawer-paper": { boxSizing: "border-box" }
7277
+ "& .MuiDrawer-paper": {
7278
+ boxSizing: "border-box",
7279
+ width: `${drawerWidth} !important`,
7280
+ minWidth: `${drawerWidth} !important`,
7281
+ maxWidth: `${drawerWidth} !important`,
7282
+ flex: `0 0 ${drawerWidth} !important`
7283
+ }
7185
7284
  },
7186
7285
  children: [
7187
7286
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
@@ -7213,7 +7312,7 @@ function AppSearchDrawer({
7213
7312
  ]
7214
7313
  }
7215
7314
  ),
7216
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material11.Box, { sx: { flex: 1, boxSizing: "border-box", overflow: "hidden", p: 3, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
7315
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material11.Box, { sx: { flex: 1, width: "100%", minWidth: 0, boxSizing: "border-box", overflow: "hidden", p: 3, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
7217
7316
  connectionPathApps && connectionPathApps.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material11.Box, { sx: { mb: 2.5 }, children: [
7218
7317
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material11.Typography, { sx: { color: "hsl(var(--muted-foreground))", fontSize: "0.7rem", fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.05em", mb: 1 }, children: "In this usecase" }),
7219
7318
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material11.Box, { sx: { display: "flex", gap: 1.5, flexWrap: "wrap" }, children: connectionPathApps.map((app) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material11.Tooltip, { title: app.name.replace(/_/g, " "), arrow: true, placement: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
@@ -7260,6 +7359,8 @@ function AppSearchDrawer({
7260
7359
  {
7261
7360
  sx: {
7262
7361
  flex: 1,
7362
+ width: "100%",
7363
+ minWidth: 0,
7263
7364
  minHeight: 0,
7264
7365
  overflow: "hidden",
7265
7366
  "& .singul-container, & .singul-search-bar-container": {
@@ -7272,16 +7373,22 @@ function AppSearchDrawer({
7272
7373
  },
7273
7374
  "& .singul-results-container": {
7274
7375
  flex: 1,
7376
+ width: "100%",
7377
+ minWidth: 0,
7275
7378
  minHeight: 0,
7276
7379
  maxHeight: "none",
7277
7380
  overflowY: "auto"
7278
7381
  },
7279
7382
  "& .singul-results-grid": {
7383
+ width: "100% !important",
7384
+ minWidth: "0 !important",
7280
7385
  gridTemplateColumns: "repeat(2, minmax(0, 1fr)) !important",
7281
7386
  gridAutoRows: "78px !important",
7282
7387
  gap: "12px !important"
7283
7388
  },
7284
7389
  "& .singul-results-grid .singul-dropdown-item": {
7390
+ width: "100%",
7391
+ maxWidth: "100%",
7285
7392
  minWidth: 0,
7286
7393
  minHeight: "78px !important",
7287
7394
  maxHeight: "78px !important",
@@ -8045,6 +8152,73 @@ function invalidateResolvedApps() {
8045
8152
  _cache.clear();
8046
8153
  }
8047
8154
 
8155
+ // llmProviderDetect.ts
8156
+ var SHUFFLE_AI_PRESET = "Shuffle AI";
8157
+ var CUSTOM_PRESET = "Custom / self-hosted";
8158
+ var ENDPOINT_PRESETS = [
8159
+ { label: SHUFFLE_AI_PRESET, url: "" },
8160
+ { 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." },
8161
+ { 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." },
8162
+ { 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." },
8163
+ { 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." },
8164
+ { 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." },
8165
+ { 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." },
8166
+ { 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." },
8167
+ { label: "OpenRouter", url: "https://openrouter.ai/api/v1", apiKeyUrl: "https://openrouter.ai/keys", apiKeyHint: "Create a key under Keys in your OpenRouter dashboard." },
8168
+ { label: "Ollama (localhost)", url: "http://localhost:11434/v1", apiKeyHint: "Local Ollama does not require an API key \u2014 any non-empty value works." },
8169
+ { 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." },
8170
+ { label: CUSTOM_PRESET, url: "" }
8171
+ ];
8172
+ var PROVIDER_DOMAINS = {
8173
+ "Shuffle AI": "shuffler.io",
8174
+ OpenAI: "openai.com",
8175
+ Anthropic: "anthropic.com",
8176
+ "Google Gemini": "gemini.google.com",
8177
+ Mistral: "mistral.ai",
8178
+ Groq: "groq.com",
8179
+ DeepSeek: "deepseek.com",
8180
+ "Together AI": "together.ai",
8181
+ OpenRouter: "openrouter.ai",
8182
+ "Ollama (localhost)": "ollama.com",
8183
+ "LM Studio (localhost)": "lmstudio.ai"
8184
+ };
8185
+ var hostnameOf = (url) => {
8186
+ try {
8187
+ return new URL(url).hostname.replace(/^www\./, "");
8188
+ } catch {
8189
+ return null;
8190
+ }
8191
+ };
8192
+ var detectLLMProvider = (url) => {
8193
+ if (!url) return null;
8194
+ const trimmed = url.trim();
8195
+ if (!trimmed) return null;
8196
+ const exact = ENDPOINT_PRESETS.find((p) => p.url && p.url === trimmed);
8197
+ if (exact) return exact;
8198
+ const host = hostnameOf(trimmed);
8199
+ if (host) {
8200
+ const byHost = ENDPOINT_PRESETS.find((p) => {
8201
+ const presetHost = hostnameOf(p.url);
8202
+ return presetHost && presetHost === host;
8203
+ });
8204
+ if (byHost) return byHost;
8205
+ if (host === "localhost" || host === "127.0.0.1") {
8206
+ if (trimmed.includes(":11434")) return ENDPOINT_PRESETS.find((p) => p.label === "Ollama (localhost)") || null;
8207
+ if (trimmed.includes(":1234")) return ENDPOINT_PRESETS.find((p) => p.label === "LM Studio (localhost)") || null;
8208
+ }
8209
+ }
8210
+ return ENDPOINT_PRESETS.find((p) => p.label === CUSTOM_PRESET) || null;
8211
+ };
8212
+ var getProviderLogoUrl = (label, url) => {
8213
+ if (!label && !url) return "";
8214
+ let domain = label ? PROVIDER_DOMAINS[label] : void 0;
8215
+ if (!domain && url) {
8216
+ const host = hostnameOf(url);
8217
+ if (host) domain = host;
8218
+ }
8219
+ return domain ? `https://www.google.com/s2/favicons?domain=${domain}&sz=64` : "";
8220
+ };
8221
+
8048
8222
  // agentRun.ts
8049
8223
  init_api();
8050
8224
  var resolveTarget = (path, opts = {}) => {
@@ -8959,10 +9133,10 @@ var AgentRunDiagnosisBanner = ({ run, sx, onJumpToEvidence, executionId }) => {
8959
9133
  const outputWarning = !isFailed && hasOutputWarning(run);
8960
9134
  const diagnosis = outputWarning ? diagnoseOutputWarning(run) : null;
8961
9135
  if (!failureInfo && !diagnosis) return null;
8962
- const isCritical = !!failureInfo;
9136
+ const isCritical = !!failureInfo || diagnosis?.kind === "token_limit";
8963
9137
  const tone = isCritical ? "critical" : "medium";
8964
9138
  const Icon = isCritical ? import_lucide_react10.AlertTriangle : import_lucide_react10.HelpCircle;
8965
- const message = isCritical ? failureInfo.reason : `${diagnosis.title} \u2014 ${diagnosis.remediation}`;
9139
+ const message = failureInfo ? failureInfo.reason : `${diagnosis.title} \u2014 ${diagnosis.remediation}`;
8966
9140
  const firstEvidence = diagnosis?.evidence?.[0] || null;
8967
9141
  const jumpDecisionIndex = firstEvidence ? extractDecisionIndex(firstEvidence.path) : null;
8968
9142
  const canJump = !!(onJumpToEvidence && jumpDecisionIndex !== null);
@@ -9501,7 +9675,7 @@ var TimelineRow = ({
9501
9675
  ),
9502
9676
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: {
9503
9677
  flex: 1,
9504
- minWidth: 0,
9678
+ minWidth: 180,
9505
9679
  fontSize: "0.85rem",
9506
9680
  color: "hsl(var(--foreground))",
9507
9681
  maxHeight: 60,
@@ -9511,7 +9685,7 @@ var TimelineRow = ({
9511
9685
  "& a": { color: "hsl(var(--primary))", textDecoration: "underline", textUnderlineOffset: "2px" },
9512
9686
  "& a:hover": { opacity: 0.85 }
9513
9687
  }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_markdown4.default, { remarkPlugins: [import_remark_gfm4.default, import_remark_breaks.default], children: normalizeMarkdown(displayLabel) }) }),
9514
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Tooltip, { title: hasTiming ? `Duration: ${dur.toFixed(2)}s \xB7 ${new Date(itemStart * 1e3).toLocaleString()}` : "No timing data", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: { width: maxWidth, position: "relative", height: 10, flexShrink: 0 }, children: dur > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: {
9688
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Tooltip, { title: hasTiming ? `Duration: ${dur.toFixed(2)}s \xB7 ${new Date(itemStart * 1e3).toLocaleString()}` : "No timing data", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: { width: maxWidth, maxWidth, minWidth: 40, position: "relative", height: 10, flexShrink: 1, flexBasis: maxWidth }, children: dur > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: {
9515
9689
  position: "absolute",
9516
9690
  left: Math.max(0, offset),
9517
9691
  width,
@@ -9919,6 +10093,7 @@ var AgentUI = ({
9919
10093
  const [chosenApps, setChosenApps] = (0, import_react15.useState)(apps ?? defaultApps ?? BUILTIN_DEFAULT_APPS);
9920
10094
  const [availableApps, setAvailableApps] = (0, import_react15.useState)([]);
9921
10095
  const [authAppsLoading, setAuthAppsLoading] = (0, import_react15.useState)(autoLoadApps && hasApiKey);
10096
+ const [detectedLLM, setDetectedLLM] = (0, import_react15.useState)(null);
9922
10097
  const [executionApps, setExecutionApps] = (0, import_react15.useState)([]);
9923
10098
  const [resolvedToolApps, setResolvedToolApps] = (0, import_react15.useState)({});
9924
10099
  const [appSearchOpen, setAppSearchOpen] = (0, import_react15.useState)(false);
@@ -9953,9 +10128,25 @@ var AgentUI = ({
9953
10128
  const [error, setError] = (0, import_react15.useState)(null);
9954
10129
  const [searchParams, setSearchParams] = (0, import_react_router_dom2.useSearchParams)();
9955
10130
  const initialViewParam = searchParams.get("agentView");
9956
- const [viewMode, setViewMode] = (0, import_react15.useState)(
9957
- initialViewParam === "detailed" ? "detailed" : "simple"
9958
- );
10131
+ const readStoredViewMode = () => {
10132
+ if (initialViewParam === "detailed") return "detailed";
10133
+ if (typeof window === "undefined") return "simple";
10134
+ try {
10135
+ const stored = window.localStorage.getItem("shuffle-agents-view-mode");
10136
+ if (stored === "detailed" || stored === "simple") return stored;
10137
+ } catch {
10138
+ }
10139
+ return "simple";
10140
+ };
10141
+ const [viewMode, setViewMode] = (0, import_react15.useState)(readStoredViewMode);
10142
+ (0, import_react15.useEffect)(() => {
10143
+ try {
10144
+ if (typeof window !== "undefined") {
10145
+ window.localStorage.setItem("shuffle-agents-view-mode", viewMode);
10146
+ }
10147
+ } catch {
10148
+ }
10149
+ }, [viewMode]);
9959
10150
  const [attachedImages, setAttachedImages] = (0, import_react15.useState)([]);
9960
10151
  const [nowTick, setNowTick] = (0, import_react15.useState)(() => Math.floor(Date.now() / 1e3));
9961
10152
  const [localRunStart, setLocalRunStart] = (0, import_react15.useState)(null);
@@ -10191,12 +10382,23 @@ var AgentUI = ({
10191
10382
  const list = Array.isArray(result) ? result : result?.data || [];
10192
10383
  const seen = /* @__PURE__ */ new Set();
10193
10384
  const loaded = [];
10385
+ let detectedFromEntries = null;
10194
10386
  for (const entry of list) {
10195
10387
  const app = entry?.app || entry;
10196
10388
  const name = app?.name;
10197
10389
  if (!name) continue;
10198
10390
  const valid = entry?.active || entry?.validation?.valid || entry?.hasValidAuth || app?.is_valid || app?.tested;
10199
10391
  if (valid === false) continue;
10392
+ if (!detectedFromEntries && (name.toLowerCase() === "openai" || app?.id === "5d19dd82517870c68d40cacad9b5ca91")) {
10393
+ const urlField = (entry?.fields || []).find((f) => (f?.key || "").toLowerCase() === "url");
10394
+ const urlVal = (urlField?.value || "").trim();
10395
+ if (urlVal) {
10396
+ const preset = detectLLMProvider(urlVal);
10397
+ if (preset) {
10398
+ detectedFromEntries = { label: preset.label, url: urlVal, logo: getProviderLogoUrl(preset.label, urlVal) };
10399
+ }
10400
+ }
10401
+ }
10200
10402
  const key = normalizeAgentAppName(name);
10201
10403
  if (seen.has(key)) continue;
10202
10404
  seen.add(key);
@@ -10208,6 +10410,7 @@ var AgentUI = ({
10208
10410
  }
10209
10411
  if (signal?.cancelled) return;
10210
10412
  setAvailableApps(loaded);
10413
+ setDetectedLLM(detectedFromEntries);
10211
10414
  } catch {
10212
10415
  } finally {
10213
10416
  if (!signal?.cancelled) setAuthAppsLoading(false);
@@ -10469,7 +10672,12 @@ var AgentUI = ({
10469
10672
  setSimpleSubmitAttempted(false);
10470
10673
  setError(null);
10471
10674
  setLocalRunStart(null);
10472
- setViewMode("simple");
10675
+ try {
10676
+ const stored = typeof window !== "undefined" ? window.localStorage.getItem("shuffle-agents-view-mode") : null;
10677
+ setViewMode(stored === "detailed" ? "detailed" : "simple");
10678
+ } catch {
10679
+ setViewMode("simple");
10680
+ }
10473
10681
  setShowStarter(false);
10474
10682
  userPickedStartRef.current = false;
10475
10683
  if (readUrlParams && typeof window !== "undefined") {
@@ -11909,8 +12117,19 @@ var AgentUI = ({
11909
12117
  "&:hover": { color: "hsl(var(--foreground))", bgcolor: "hsl(var(--muted) / 0.5)" }
11910
12118
  },
11911
12119
  children: [
11912
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.Settings, { size: 14 }),
11913
- "Choose LLM"
12120
+ detectedLLM?.logo ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
12121
+ import_material16.Box,
12122
+ {
12123
+ component: "img",
12124
+ src: detectedLLM.logo,
12125
+ alt: "",
12126
+ sx: { width: 14, height: 14, borderRadius: "3px", objectFit: "contain", display: "block" },
12127
+ onError: (e) => {
12128
+ e.currentTarget.style.display = "none";
12129
+ }
12130
+ }
12131
+ ) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.Settings, { size: 14 }),
12132
+ detectedLLM?.label || "Choose LLM"
11914
12133
  ]
11915
12134
  }
11916
12135
  ) }),
@@ -12144,7 +12363,7 @@ var AgentUI = ({
12144
12363
  AgentRunDiagnosisBanner_default,
12145
12364
  {
12146
12365
  run: execution?.results?.length ? execution : agentData,
12147
- sx: { px: 0, pb: 0, mb: 2 },
12366
+ sx: { px: 1.5, pb: 0, mb: 2 },
12148
12367
  executionId: execution?.execution_id,
12149
12368
  onJumpToEvidence: (decisionIndex) => {
12150
12369
  const dec = (agentData?.decisions || [])[decisionIndex];
@@ -12369,14 +12588,14 @@ var AgentUI = ({
12369
12588
  ] })
12370
12589
  ] });
12371
12590
  })() : !finishAnswer && isRunning ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Typography, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "Waiting for the agent to produce the first step." }) : !finishAnswer ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Typography, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "No final answer was returned. Open Detailed to inspect each step." }) : null,
12372
- !isRunning && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
12591
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
12373
12592
  import_material16.Button,
12374
12593
  {
12375
12594
  size: "small",
12376
12595
  variant: "text",
12377
12596
  onClick: () => setViewMode("detailed"),
12378
12597
  sx: { color: "hsl(var(--primary))", textTransform: "none", px: 0 },
12379
- children: "View detailed timeline \u2192"
12598
+ children: isRunning ? "View live detailed timeline \u2192" : "View detailed timeline \u2192"
12380
12599
  }
12381
12600
  ) })
12382
12601
  ] });
@@ -12657,8 +12876,6 @@ var import_jsx_runtime22 = require("react/jsx-runtime");
12657
12876
  var import_react17 = require("react");
12658
12877
  var OPENAI_APP_NAME = "OpenAI";
12659
12878
  var OPENAI_APP_ID = "5d19dd82517870c68d40cacad9b5ca91";
12660
- var SHUFFLE_AI_PRESET = "Shuffle AI";
12661
- var CUSTOM_PRESET = "Custom / self-hosted";
12662
12879
  var OPENAI_ALGOLIA_APP = {
12663
12880
  name: OPENAI_APP_NAME,
12664
12881
  description: "OpenAI-compatible LLM endpoint for agent operations",
@@ -12678,32 +12895,18 @@ var OPENAI_ALGOLIA_APP = {
12678
12895
  triggers: [],
12679
12896
  verified: true
12680
12897
  };
12681
- var ENDPOINT_PRESETS = [
12682
- { label: SHUFFLE_AI_PRESET, url: "" },
12683
- { 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." },
12684
- { 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." },
12685
- { 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." },
12686
- { 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." },
12687
- { 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." },
12688
- { 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." },
12689
- { 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." },
12690
- { label: "OpenRouter", url: "https://openrouter.ai/api/v1", apiKeyUrl: "https://openrouter.ai/keys", apiKeyHint: "Create a key under Keys in your OpenRouter dashboard." },
12691
- { label: "Ollama (localhost)", url: "http://localhost:11434/v1", apiKeyHint: "Local Ollama does not require an API key \u2014 any non-empty value works." },
12692
- { 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." },
12693
- { label: CUSTOM_PRESET, url: "" }
12694
- ];
12695
- var PROVIDER_DOMAINS = {
12696
- "Shuffle AI": "shuffler.io",
12697
- OpenAI: "openai.com",
12698
- Anthropic: "anthropic.com",
12699
- "Google Gemini": "gemini.google.com",
12700
- Mistral: "mistral.ai",
12701
- Groq: "groq.com",
12702
- DeepSeek: "deepseek.com",
12703
- "Together AI": "together.ai",
12704
- OpenRouter: "openrouter.ai",
12705
- "Ollama (localhost)": "ollama.com",
12706
- "LM Studio (localhost)": "lmstudio.ai"
12898
+ var CUSTOM_MODEL = "Custom\u2026";
12899
+ var PROVIDER_MODELS = {
12900
+ 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"],
12901
+ Anthropic: ["claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5", "claude-opus-4", "claude-sonnet-4", "claude-3-7-sonnet-latest"],
12902
+ "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"],
12903
+ Mistral: ["mistral-large-2026", "mistral-medium-3", "mistral-small-3.2", "codestral-2026", "magistral-medium-2026", "ministral-8b-latest"],
12904
+ 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"],
12905
+ DeepSeek: ["deepseek-v3.5", "deepseek-v3", "deepseek-r1", "deepseek-coder-v3"],
12906
+ "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"],
12907
+ 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"],
12908
+ "Ollama (localhost)": ["llama3.3", "llama3.2", "qwen3", "qwen3:32b", "deepseek-r1", "deepseek-r1:70b", "mistral-small3", "phi4", "gemma3"],
12909
+ "LM Studio (localhost)": ["llama-3.3-70b-instruct", "qwen3-32b", "deepseek-r1-distill-qwen-32b", "mistral-small-3", "phi-4", "gemma-3-27b"]
12707
12910
  };
12708
12911
  var ProviderLogo = ({ label, url }) => {
12709
12912
  const [errored, setErrored] = (0, import_react16.useState)(false);
@@ -12733,46 +12936,16 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
12733
12936
  status: "pending",
12734
12937
  credentials: {}
12735
12938
  };
12736
- const currentUrl = authState.credentials?.url || "";
12737
- const attemptedDeletionRef = (0, import_react16.useRef)(/* @__PURE__ */ new Set());
12738
- (0, import_react16.useEffect)(() => {
12739
- if (authState.status === "testing") return;
12740
- const failedEntries = openaiEntries.filter((e) => e.validation && e.validation.valid === false && e.id);
12741
- if (failedEntries.length === 0) return;
12742
- let cancelled = false;
12743
- (async () => {
12744
- let deletedAny = false;
12745
- for (const entry of failedEntries) {
12746
- const id = entry.id;
12747
- if (attemptedDeletionRef.current.has(id)) continue;
12748
- attemptedDeletionRef.current.add(id);
12749
- try {
12750
- const resp = await fetch(getApiUrl(`/api/v1/apps/authentication/${id}`), {
12751
- method: "DELETE",
12752
- credentials: "include",
12753
- headers: { ...getAuthHeader() }
12754
- });
12755
- if (resp.ok) deletedAny = true;
12756
- } catch (err) {
12757
- console.error("[LocalLLMConfig] Failed to auto-delete failed OpenAI auth:", err);
12758
- }
12759
- }
12760
- if (!cancelled && deletedAny) {
12761
- await refreshAuth();
12762
- refreshAllIntegrationStatus();
12763
- }
12764
- })();
12765
- return () => {
12766
- cancelled = true;
12767
- };
12768
- }, [openaiEntries, authState.status, refreshAuth]);
12939
+ const savedUrlFromEntry = (openaiEntries[0]?.fields || []).find((f) => (f?.key || "").toLowerCase() === "url")?.value || "";
12940
+ const currentUrl = (authState.credentials?.url || savedUrlFromEntry || "").trim();
12941
+ const [customModel, setCustomModel] = (0, import_react16.useState)("");
12942
+ const [customMode, setCustomMode] = (0, import_react16.useState)(false);
12769
12943
  const hasOpenAIEntries = openaiEntries.length > 0;
12770
12944
  const effectivePreset = (0, import_react16.useMemo)(() => {
12771
12945
  if (selectedPreset) return selectedPreset;
12772
12946
  if (!currentUrl && !hasOpenAIEntries) return SHUFFLE_AI_PRESET;
12773
12947
  if (!currentUrl) return "";
12774
- const match = ENDPOINT_PRESETS.find((p) => p.url && p.url === currentUrl);
12775
- return match ? match.label : CUSTOM_PRESET;
12948
+ return detectLLMProvider(currentUrl)?.label || CUSTOM_PRESET;
12776
12949
  }, [selectedPreset, currentUrl, hasOpenAIEntries]);
12777
12950
  const applyShuffleAI = async () => {
12778
12951
  let deletedAny = false;
@@ -12809,7 +12982,16 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
12809
12982
  setSelectedPreset(label);
12810
12983
  const preset = ENDPOINT_PRESETS.find((p) => p.label === label);
12811
12984
  if (!preset) return;
12812
- handleAuthChange(OPENAI_APP_ID, { ...authState.credentials, url: preset.label === CUSTOM_PRESET ? customUrl : preset.url });
12985
+ const topModel = PROVIDER_MODELS[label]?.[0] || "";
12986
+ const existingModel = authState.credentials?.model || "";
12987
+ const nextModel = topModel || existingModel;
12988
+ setCustomMode(false);
12989
+ setCustomModel("");
12990
+ handleAuthChange(OPENAI_APP_ID, {
12991
+ ...authState.credentials,
12992
+ url: preset.label === CUSTOM_PRESET ? customUrl : preset.url,
12993
+ ...nextModel ? { model: nextModel } : {}
12994
+ });
12813
12995
  };
12814
12996
  const handleCustomUrlChange = (value) => {
12815
12997
  setCustomUrl(value);
@@ -12884,7 +13066,7 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
12884
13066
  );
12885
13067
  },
12886
13068
  slotProps: {
12887
- paper: { sx: { bgcolor: "hsl(var(--popover))", color: "hsl(var(--popover-foreground))", border: "1px solid hsl(var(--border))" } },
13069
+ paper: { sx: { bgcolor: "hsl(var(--popover))", color: "hsl(var(--popover-foreground))", border: "1px solid hsl(var(--border))", minWidth: 580 } },
12888
13070
  popper: { sx: { zIndex: 9999 } }
12889
13071
  }
12890
13072
  }
@@ -12947,6 +13129,59 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
12947
13129
  hideDocsLink: true,
12948
13130
  hideUrlFields: true,
12949
13131
  borderless: true,
13132
+ compactAuthForm: true,
13133
+ extraFieldsSlot: (PROVIDER_MODELS[effectivePreset]?.length ?? 0) > 0 ? ({ credentials, setField }) => {
13134
+ const liveModel = credentials.model || "";
13135
+ const presetModels = PROVIDER_MODELS[effectivePreset] || [];
13136
+ const liveIsCustom = liveModel !== "" && !presetModels.includes(liveModel);
13137
+ const showCustom = customMode || liveIsCustom;
13138
+ const liveSelectValue = showCustom ? CUSTOM_MODEL : liveModel || null;
13139
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Box, { sx: { display: "flex", flexDirection: "column", gap: 1 }, children: [
13140
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Typography, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: "Model" }),
13141
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
13142
+ import_material18.Autocomplete,
13143
+ {
13144
+ size: "small",
13145
+ fullWidth: true,
13146
+ disableClearable: true,
13147
+ options: [...presetModels, CUSTOM_MODEL],
13148
+ value: liveSelectValue,
13149
+ onChange: (_e, val) => {
13150
+ if (!val) return;
13151
+ if (val === CUSTOM_MODEL) {
13152
+ setCustomMode(true);
13153
+ setField("model", customModel);
13154
+ } else {
13155
+ setCustomMode(false);
13156
+ setCustomModel("");
13157
+ setField("model", val);
13158
+ }
13159
+ },
13160
+ isOptionEqualToValue: (opt, val) => opt === val,
13161
+ slotProps: {
13162
+ paper: { sx: { bgcolor: "hsl(var(--popover))", color: "hsl(var(--popover-foreground))", border: "1px solid hsl(var(--border))" } },
13163
+ popper: { sx: { zIndex: 9999 } }
13164
+ },
13165
+ renderInput: (params) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.TextField, { ...params, placeholder: "Select a model\u2026" })
13166
+ }
13167
+ ),
13168
+ showCustom && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
13169
+ import_material18.TextField,
13170
+ {
13171
+ size: "small",
13172
+ fullWidth: true,
13173
+ placeholder: "Enter a custom model identifier",
13174
+ value: customModel || (liveIsCustom ? liveModel : ""),
13175
+ onChange: (e) => {
13176
+ setCustomModel(e.target.value);
13177
+ setField("model", e.target.value);
13178
+ },
13179
+ helperText: "Exact model name as expected by the provider's API",
13180
+ sx: { "& .MuiFormHelperText-root": { color: "hsl(var(--muted-foreground))" } }
13181
+ }
13182
+ )
13183
+ ] });
13184
+ } : void 0,
12950
13185
  globalUrl,
12951
13186
  userdata,
12952
13187
  isLoaded,
@@ -13024,9 +13259,16 @@ var AgentRunDrawer = ({
13024
13259
  setActiveTab("localLLM");
13025
13260
  }
13026
13261
  };
13262
+ const onClose2 = () => {
13263
+ onClose();
13264
+ };
13027
13265
  window.addEventListener("agent-drawer-open", onOpen);
13028
- return () => window.removeEventListener("agent-drawer-open", onOpen);
13029
- }, []);
13266
+ window.addEventListener("agent-drawer-close", onClose2);
13267
+ return () => {
13268
+ window.removeEventListener("agent-drawer-open", onOpen);
13269
+ window.removeEventListener("agent-drawer-close", onClose2);
13270
+ };
13271
+ }, [onClose]);
13030
13272
  const effectiveLocalLLMSlot = localLLMSlot ?? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13031
13273
  LocalLLMConfig_default,
13032
13274
  {
@@ -13498,7 +13740,7 @@ var STATUS_CONFIG = {
13498
13740
  EXECUTING: { icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Loader2, { size: 16 }), color: "hsl(var(--severity-medium, 38 92% 50%))", label: "Running" },
13499
13741
  RUNNING: { icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Loader2, { size: 16 }), color: "hsl(var(--severity-medium, 38 92% 50%))", label: "Running" },
13500
13742
  WAITING: { icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Clock, { size: 16 }), color: "hsl(var(--severity-info, 217 91% 60%))", label: "Waiting" },
13501
- LIMIT_REACHED: { icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react14.AlertTriangle, { size: 16 }), color: "hsl(var(--severity-medium, 38 92% 50%))", label: "Limit reached" }
13743
+ LIMIT_REACHED: { icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react14.AlertTriangle, { size: 16 }), color: "hsl(var(--severity-critical, 0 72% 55%))", label: "Limit reached" }
13502
13744
  };
13503
13745
  var getEffectiveStatus = (run) => {
13504
13746
  const raw = (run.status || "").toUpperCase();
@@ -13511,21 +13753,126 @@ var getEffectiveStatus = (run) => {
13511
13753
  }
13512
13754
  return raw;
13513
13755
  };
13514
- var getRunIcon = (run) => {
13515
- const src = (run.execution_source || "").toLowerCase();
13516
- const arg = (run.execution_argument || "").toLowerCase();
13517
- if (src.includes("schedule") || src.includes("cron")) return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Clock, { size: 18 });
13518
- if (src.includes("webhook") || src.includes("http")) return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Globe, { size: 18 });
13519
- if (arg.includes("alert") || arg.includes("detect")) return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Activity, { size: 18 });
13520
- if (arg.includes("report") || arg.includes("email")) return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.FileText, { size: 18 });
13521
- if (arg.includes("endpoint") || arg.includes("server")) return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Server, { size: 18 });
13522
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Zap, { size: 18 });
13756
+ var SOURCE_ICON_SIZE = 18;
13757
+ 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());
13758
+ var DATASTORE_KEY_RE = /\bKey:\s*(\S+)/i;
13759
+ var DATASTORE_CATEGORY_RE = /\bCategory:\s*(\S+)/i;
13760
+ var parseDatastoreTask = (arg) => {
13761
+ if (!arg) return null;
13762
+ const k = arg.match(DATASTORE_KEY_RE);
13763
+ const c = arg.match(DATASTORE_CATEGORY_RE);
13764
+ if (!k || !c) return null;
13765
+ const key = (k[1] || "").trim();
13766
+ const category = (c[1] || "").trim();
13767
+ if (!key || !category) return null;
13768
+ return { key, category };
13769
+ };
13770
+ var isAIAgentResult = (result) => String(result?.action?.app_name || "").trim().toLowerCase() === "ai agent";
13771
+ var getAIAgentResultPayload = (run) => {
13772
+ const results = Array.isArray(run.results) ? run.results : [];
13773
+ const agentResult = results.find(isAIAgentResult);
13774
+ if (!agentResult || typeof agentResult !== "object" || !("result" in agentResult)) return null;
13775
+ return tryParseJson(agentResult.result);
13776
+ };
13777
+ var getDirectAgentInput = (payload) => {
13778
+ if (!payload || typeof payload !== "object") return null;
13779
+ const obj = payload;
13780
+ if (typeof obj.original_input === "string" && obj.original_input.trim()) {
13781
+ return obj.original_input.trim();
13782
+ }
13783
+ if (typeof obj.input === "string" && obj.input.trim()) {
13784
+ return obj.input.trim();
13785
+ }
13786
+ return null;
13787
+ };
13788
+ var findDatastoreTaskInRun = (run) => {
13789
+ const agentInput = getDirectAgentInput(getAIAgentResultPayload(run));
13790
+ const agentHit = parseDatastoreTask(agentInput || void 0);
13791
+ if (agentHit) return agentHit;
13792
+ const anyRun = run;
13793
+ const candidates = [];
13794
+ if (typeof anyRun.original_input === "string") candidates.push(anyRun.original_input);
13795
+ if (typeof anyRun.input === "string") candidates.push(anyRun.input);
13796
+ if (run.execution_argument) candidates.push(run.execution_argument);
13797
+ if (run.result) candidates.push(run.result);
13798
+ if (Array.isArray(anyRun.results)) {
13799
+ try {
13800
+ candidates.push(JSON.stringify(anyRun.results));
13801
+ } catch {
13802
+ }
13803
+ }
13804
+ for (const c of candidates) {
13805
+ const hit = parseDatastoreTask(c);
13806
+ if (hit) return hit;
13807
+ }
13808
+ return null;
13809
+ };
13810
+ var classifyRunSource = (run) => {
13811
+ const raw = (run.execution_source || "").trim();
13812
+ const src = raw.toLowerCase();
13813
+ const ds = findDatastoreTaskInRun(run);
13814
+ if (ds || src.includes("datastore") || src.includes("enrichment") || src.includes("automation")) {
13815
+ return {
13816
+ kind: "datastore",
13817
+ label: "Datastore automation",
13818
+ 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).",
13819
+ icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Database, { size: SOURCE_ICON_SIZE }),
13820
+ datastoreKey: ds?.key,
13821
+ datastoreCategory: ds?.category
13822
+ };
13823
+ }
13824
+ if (src.includes("schedule") || src.includes("cron")) {
13825
+ return {
13826
+ kind: "schedule",
13827
+ label: "Schedule",
13828
+ reason: "Started by a scheduled trigger (cron).",
13829
+ icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Clock, { size: SOURCE_ICON_SIZE })
13830
+ };
13831
+ }
13832
+ if (src.includes("webhook") || src.includes("http")) {
13833
+ return {
13834
+ kind: "webhook",
13835
+ label: "Webhook",
13836
+ reason: "Started by an incoming webhook / HTTP trigger.",
13837
+ icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Globe, { size: SOURCE_ICON_SIZE })
13838
+ };
13839
+ }
13840
+ if (src.includes("form")) {
13841
+ return {
13842
+ kind: "form",
13843
+ label: "Form",
13844
+ reason: "Started by a form submission.",
13845
+ icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.FileText, { size: SOURCE_ICON_SIZE })
13846
+ };
13847
+ }
13848
+ if (raw && looksLikeExecutionId(raw)) {
13849
+ return {
13850
+ kind: "workflow",
13851
+ label: "Workflow",
13852
+ reason: "Started by another workflow as a subflow.",
13853
+ icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Workflow, { size: SOURCE_ICON_SIZE })
13854
+ };
13855
+ }
13856
+ if (src === "" || src === "manual" || src === "default" || src === "demo") {
13857
+ return {
13858
+ kind: "manual",
13859
+ label: "Manual",
13860
+ reason: "Started manually from the Agents UI.",
13861
+ icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Hand, { size: SOURCE_ICON_SIZE })
13862
+ };
13863
+ }
13864
+ return {
13865
+ kind: "unknown",
13866
+ label: raw || "Unknown",
13867
+ reason: raw ? `Started by "${raw}".` : "Trigger source unknown.",
13868
+ icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.Zap, { size: SOURCE_ICON_SIZE })
13869
+ };
13523
13870
  };
13524
13871
  var getRunIconColor = (run) => {
13525
13872
  const status = getEffectiveStatus(run);
13526
13873
  if (status === "FINISHED" || status === "SUCCESS") return "hsl(var(--severity-low, 142 71% 45%))";
13527
13874
  if (status === "FAILED" || status === "ABORTED") return "hsl(var(--severity-critical, 0 72% 55%))";
13528
- if (status === "LIMIT_REACHED") return "hsl(var(--severity-medium, 38 92% 50%))";
13875
+ if (status === "LIMIT_REACHED") return "hsl(var(--severity-critical, 0 72% 55%))";
13529
13876
  if (status === "EXECUTING" || status === "RUNNING") return "hsl(var(--severity-medium, 38 92% 50%))";
13530
13877
  return "hsl(var(--primary, 24 100% 50%))";
13531
13878
  };
@@ -13623,9 +13970,12 @@ var tryParseJson = (s) => {
13623
13970
  }
13624
13971
  };
13625
13972
  var getRunPrompt = (run) => {
13626
- const results = Array.isArray(run.results) ? run.results : null;
13973
+ const anyRun = run;
13974
+ const agentInput = getDirectAgentInput(getAIAgentResultPayload(run));
13975
+ if (agentInput) return agentInput;
13976
+ const results = Array.isArray(anyRun.results) ? anyRun.results : null;
13627
13977
  if (results) {
13628
- const agentResult = results.find((r) => r?.action?.app_name === "AI Agent");
13978
+ const agentResult = results.find(isAIAgentResult);
13629
13979
  if (agentResult?.result) {
13630
13980
  const hit = deepFindPrompt(tryParseJson(agentResult.result));
13631
13981
  if (hit) return hit;
@@ -13636,6 +13986,12 @@ var getRunPrompt = (run) => {
13636
13986
  if (hit) return hit;
13637
13987
  }
13638
13988
  }
13989
+ if (typeof anyRun.original_input === "string" && anyRun.original_input.trim()) {
13990
+ return anyRun.original_input.trim();
13991
+ }
13992
+ if (typeof anyRun.input === "string" && anyRun.input.trim()) {
13993
+ return anyRun.input.trim();
13994
+ }
13639
13995
  if (run.result) {
13640
13996
  const hit = deepFindPrompt(tryParseJson(run.result));
13641
13997
  if (hit) return hit;
@@ -13676,7 +14032,9 @@ var getRunSubtitle = (run) => {
13676
14032
  if (run.result.length < 120) return run.result;
13677
14033
  }
13678
14034
  }
13679
- return run.execution_source || "Agent execution";
14035
+ const status = getEffectiveStatus(run);
14036
+ const isRunning = status === "EXECUTING" || status === "RUNNING" || status === "WAITING";
14037
+ return run.execution_source || (isRunning ? "Agent still running\u2026" : "Agent execution");
13680
14038
  };
13681
14039
  var normalizeResultStatus = (s) => {
13682
14040
  const v = (s || "").toUpperCase();
@@ -13778,41 +14136,60 @@ var AgentRunRow = ({ run, onClick, sx, appIcons, onAppClick }) => {
13778
14136
  ...Array.isArray(sx) ? sx : sx ? [sx] : []
13779
14137
  ],
13780
14138
  children: [
13781
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13782
- import_material20.Box,
13783
- {
13784
- sx: {
13785
- width: 40,
13786
- height: 40,
13787
- borderRadius: "50%",
13788
- display: "flex",
13789
- alignItems: "center",
13790
- justifyContent: "center",
13791
- bgcolor: `${iconColor}15`,
13792
- color: iconColor,
13793
- flexShrink: 0
13794
- },
13795
- children: getRunIcon(run)
13796
- }
13797
- ),
14139
+ (() => {
14140
+ const sourceInfo = classifyRunSource(run);
14141
+ const dsLink = sourceInfo.kind === "datastore" && sourceInfo.datastoreKey && sourceInfo.datastoreCategory ? `https://shuffler.io/admin?tab=datastore&category=${encodeURIComponent(sourceInfo.datastoreCategory)}&key=${encodeURIComponent(sourceInfo.datastoreKey)}` : null;
14142
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
14143
+ import_material20.Tooltip,
14144
+ {
14145
+ title: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_material20.Box, { sx: { lineHeight: 1.4 }, children: [
14146
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Box, { sx: { fontWeight: 600 }, children: sourceInfo.label }),
14147
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Box, { sx: { opacity: 0.85 }, children: sourceInfo.reason })
14148
+ ] }),
14149
+ placement: "top",
14150
+ arrow: true,
14151
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
14152
+ import_material20.Box,
14153
+ {
14154
+ onClick: dsLink ? (e) => {
14155
+ e.stopPropagation();
14156
+ window.open(dsLink, "_blank", "noopener,noreferrer");
14157
+ } : void 0,
14158
+ sx: {
14159
+ width: 40,
14160
+ height: 40,
14161
+ borderRadius: "50%",
14162
+ display: "flex",
14163
+ alignItems: "center",
14164
+ justifyContent: "center",
14165
+ bgcolor: `${iconColor}15`,
14166
+ color: iconColor,
14167
+ flexShrink: 0,
14168
+ cursor: dsLink ? "pointer" : "inherit",
14169
+ transition: "background 0.15s ease",
14170
+ "&:hover": dsLink ? { bgcolor: `${iconColor}30` } : void 0
14171
+ },
14172
+ children: sourceInfo.icon
14173
+ }
14174
+ )
14175
+ }
14176
+ );
14177
+ })(),
13798
14178
  /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_material20.Box, { sx: { flex: 1, minWidth: 0 }, children: [
13799
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_material20.Box, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 0.25 }, children: [
13800
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13801
- import_material20.Typography,
13802
- {
13803
- sx: {
13804
- fontSize: "0.9rem",
13805
- fontWeight: 500,
13806
- color: "hsl(var(--foreground))",
13807
- overflow: "hidden",
13808
- textOverflow: "ellipsis",
13809
- whiteSpace: "nowrap"
13810
- },
13811
- children: getRunTitle(run)
13812
- }
13813
- ),
13814
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Box, { sx: { display: "flex", alignItems: "center", color: cfg.color, flexShrink: 0 }, children: cfg.icon })
13815
- ] }),
14179
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Box, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 0.25 }, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
14180
+ import_material20.Typography,
14181
+ {
14182
+ sx: {
14183
+ fontSize: "0.9rem",
14184
+ fontWeight: 500,
14185
+ color: "hsl(var(--foreground))",
14186
+ overflow: "hidden",
14187
+ textOverflow: "ellipsis",
14188
+ whiteSpace: "nowrap"
14189
+ },
14190
+ children: getRunTitle(run)
14191
+ }
14192
+ ) }),
13816
14193
  /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13817
14194
  import_material20.Typography,
13818
14195
  {
@@ -13907,18 +14284,7 @@ var AgentRunRow = ({ run, onClick, sx, appIcons, onAppClick }) => {
13907
14284
  ) }, t.name);
13908
14285
  })
13909
14286
  }
13910
- ) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13911
- import_material20.Typography,
13912
- {
13913
- sx: {
13914
- fontSize: "0.7rem",
13915
- color: "hsl(var(--muted-foreground))",
13916
- opacity: 0.5,
13917
- fontStyle: "italic"
13918
- },
13919
- children: "No apps"
13920
- }
13921
- )
14287
+ ) : null
13922
14288
  }
13923
14289
  )
13924
14290
  ]
@@ -14739,6 +15105,15 @@ var AgentsView = ({
14739
15105
  open: false,
14740
15106
  tab: "localLLM"
14741
15107
  });
15108
+ (0, import_react20.useEffect)(() => {
15109
+ if (typeof window === "undefined") return;
15110
+ const handler = (e) => {
15111
+ const detail = e.detail;
15112
+ setBuiltInDrawer({ open: true, tab: detail?.tab ?? "localLLM" });
15113
+ };
15114
+ window.addEventListener("agent-drawer-open", handler);
15115
+ return () => window.removeEventListener("agent-drawer-open", handler);
15116
+ }, []);
14742
15117
  const effectiveSchedule = (0, import_react20.useCallback)(
14743
15118
  async (info) => {
14744
15119
  if (onSchedule) return onSchedule(info);