@acarmisc/backstage-plugin-litellm 0.21.3 → 0.23.0

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.esm.js CHANGED
@@ -2001,6 +2001,8 @@ var init_ManageTeamDialog = __esm({
2001
2001
  const [mcpError, setMcpError] = useState3(null);
2002
2002
  const allowUnlimitedBudget = config?.teamManagement?.allowUnlimitedBudget ?? false;
2003
2003
  const maxBudgetCeiling = config?.teamManagement?.maxBudgetCeiling ?? FALLBACK_BUDGET_CEILING;
2004
+ const hideBudgetForManagers = config?.display?.hideTeamBudgetForManagers ?? false;
2005
+ const budgetWriteOnly = hideBudgetForManagers && mode === "edit";
2004
2006
  const members = useMemo4(() => team?.members_with_roles ?? [], [team]);
2005
2007
  const showMembers = mode === "edit" && !!canManageMembers;
2006
2008
  const catalogApi = useApi(catalogApiRef);
@@ -2036,9 +2038,13 @@ var init_ManageTeamDialog = __esm({
2036
2038
  if (mode === "edit" && team) {
2037
2039
  setAlias(team.team_alias ?? "");
2038
2040
  setModels(team.models ?? []);
2039
- setMaxBudget(
2040
- team.max_budget ? String(team.max_budget) : String(maxBudgetCeiling)
2041
- );
2041
+ if (hideBudgetForManagers) {
2042
+ setMaxBudget("");
2043
+ } else {
2044
+ setMaxBudget(
2045
+ team.max_budget ? String(team.max_budget) : String(maxBudgetCeiling)
2046
+ );
2047
+ }
2042
2048
  setUnlimited(allowUnlimitedBudget && !team.max_budget);
2043
2049
  setBudgetDuration(team.budget_duration ?? DEFAULT_BUDGET_DURATION);
2044
2050
  } else {
@@ -2058,7 +2064,7 @@ var init_ManageTeamDialog = __esm({
2058
2064
  setMcpIds(team?.object_permission?.mcp_servers ?? []);
2059
2065
  setMcpError(null);
2060
2066
  }
2061
- }, [open, mode, team, allowUnlimitedBudget, maxBudgetCeiling]);
2067
+ }, [open, mode, team, allowUnlimitedBudget, maxBudgetCeiling, hideBudgetForManagers]);
2062
2068
  const handleSubmit = async () => {
2063
2069
  setError(null);
2064
2070
  if (!alias.trim()) {
@@ -2070,18 +2076,21 @@ var init_ManageTeamDialog = __esm({
2070
2076
  return;
2071
2077
  }
2072
2078
  if (!unlimited) {
2073
- if (!maxBudget) {
2074
- setError("Budget is required when unlimited budgets are disabled");
2075
- return;
2076
- }
2077
- const budget = parseFloat(maxBudget);
2078
- if (isNaN(budget) || budget <= 0) {
2079
- setError("Budget must be a positive number");
2080
- return;
2081
- }
2082
- if (budget > maxBudgetCeiling) {
2083
- setError(`Budget cannot exceed $${maxBudgetCeiling}`);
2084
- return;
2079
+ const budgetLeftBlank = budgetWriteOnly && !maxBudget.trim();
2080
+ if (!budgetLeftBlank) {
2081
+ if (!maxBudget) {
2082
+ setError("Budget is required when unlimited budgets are disabled");
2083
+ return;
2084
+ }
2085
+ const budget = parseFloat(maxBudget);
2086
+ if (isNaN(budget) || budget <= 0) {
2087
+ setError("Budget must be a positive number");
2088
+ return;
2089
+ }
2090
+ if (budget > maxBudgetCeiling) {
2091
+ setError(`Budget cannot exceed $${maxBudgetCeiling}`);
2092
+ return;
2093
+ }
2085
2094
  }
2086
2095
  }
2087
2096
  try {
@@ -2095,10 +2104,16 @@ var init_ManageTeamDialog = __esm({
2095
2104
  ...budgetDuration && { budget_duration: budgetDuration }
2096
2105
  };
2097
2106
  } else {
2107
+ let budgetField = {};
2108
+ if (unlimited) {
2109
+ budgetField = { max_budget: null };
2110
+ } else if (maxBudget.trim()) {
2111
+ budgetField = { max_budget: parseFloat(maxBudget) };
2112
+ }
2098
2113
  payload = {
2099
2114
  team_alias: alias.trim(),
2100
2115
  models,
2101
- ...unlimited ? { max_budget: null } : { max_budget: parseFloat(maxBudget) },
2116
+ ...budgetField,
2102
2117
  ...budgetDuration && { budget_duration: budgetDuration }
2103
2118
  };
2104
2119
  }
@@ -2204,13 +2219,13 @@ var init_ManageTeamDialog = __esm({
2204
2219
  ), /* @__PURE__ */ React5.createElement(
2205
2220
  TextField3,
2206
2221
  {
2207
- label: "Max Budget ($)",
2222
+ label: budgetWriteOnly ? "New Max Budget ($)" : "Max Budget ($)",
2208
2223
  type: "number",
2209
2224
  value: maxBudget,
2210
2225
  onChange: (e) => setMaxBudget(e.target.value),
2211
2226
  disabled: submitting || unlimited,
2212
2227
  inputProps: { min: 0, max: maxBudgetCeiling },
2213
- helperText: `Maximum: $${maxBudgetCeiling}`,
2228
+ helperText: budgetWriteOnly ? "Current budget is hidden \u2014 leave blank to keep it, or enter a new value" : `Maximum: $${maxBudgetCeiling}`,
2214
2229
  fullWidth: true
2215
2230
  }
2216
2231
  ), allowUnlimitedBudget && /* @__PURE__ */ React5.createElement(
@@ -2781,7 +2796,19 @@ function buildBudgetSummary(user, teams, keys, maxKeys = 3) {
2781
2796
  pct: limitPct(spend, budget)
2782
2797
  };
2783
2798
  })() : void 0;
2784
- const teamLimits = teams.filter((t) => (t.max_budget ?? 0) > 0).map((t) => {
2799
+ const teamLimits = teams.filter((t) => (t.max_budget ?? 0) > 0 || t.budget_hidden === true).map((t) => {
2800
+ if (t.budget_hidden === true) {
2801
+ return {
2802
+ kind: "team",
2803
+ label: t.team_alias || "Untitled team",
2804
+ sublabel: t.team_id,
2805
+ budget: 0,
2806
+ spend: 0,
2807
+ budgetDuration: t.budget_duration,
2808
+ pct: Math.min(100, Math.max(0, t.budget_pct ?? 0)),
2809
+ hidden: true
2810
+ };
2811
+ }
2785
2812
  const spend = t.spend ?? 0;
2786
2813
  return {
2787
2814
  kind: "team",
@@ -2957,7 +2984,7 @@ var init_LiteLLMBudgetWidget = __esm({
2957
2984
  }
2958
2985
  },
2959
2986
  limit.sublabel
2960
- )), /* @__PURE__ */ React7.createElement(Typography7, { variant: "body2", sx: { fontWeight: 600, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" } }, fmtUsd(limit.spend), /* @__PURE__ */ React7.createElement(Box7, { component: "span", color: "text.secondary", sx: { fontWeight: 400 } }, " / ", fmtUsd(limit.budget)))), /* @__PURE__ */ React7.createElement(Box7, { sx: { mt: 1 } }, /* @__PURE__ */ React7.createElement(Meter, { value: limit.pct, tone, height: 6 })), /* @__PURE__ */ React7.createElement(
2987
+ )), limit.hidden ? /* @__PURE__ */ React7.createElement(Typography7, { variant: "body2", sx: { fontWeight: 600, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" } }, pct, "% used") : /* @__PURE__ */ React7.createElement(Typography7, { variant: "body2", sx: { fontWeight: 600, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" } }, fmtUsd(limit.spend), /* @__PURE__ */ React7.createElement(Box7, { component: "span", color: "text.secondary", sx: { fontWeight: 400 } }, " / ", fmtUsd(limit.budget)))), /* @__PURE__ */ React7.createElement(Box7, { sx: { mt: 1 } }, /* @__PURE__ */ React7.createElement(Meter, { value: limit.pct, tone, height: 6 })), /* @__PURE__ */ React7.createElement(
2961
2988
  Box7,
2962
2989
  {
2963
2990
  sx: {
@@ -2968,7 +2995,7 @@ var init_LiteLLMBudgetWidget = __esm({
2968
2995
  mt: 0.75
2969
2996
  }
2970
2997
  },
2971
- /* @__PURE__ */ React7.createElement(Typography7, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, pct, "% of budget", closeTo && ` \xB7 soft-limit warning`),
2998
+ /* @__PURE__ */ React7.createElement(Typography7, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, limit.hidden ? /* @__PURE__ */ React7.createElement(React7.Fragment, null, "Hidden by admin") : /* @__PURE__ */ React7.createElement(React7.Fragment, null, pct, "% of budget", closeTo && ` \xB7 soft-limit warning`)),
2972
2999
  /* @__PURE__ */ React7.createElement(Typography7, { variant: "caption", color: "text.secondary" }, fmtBudgetDuration(limit.budgetDuration) ? `resets ${fmtBudgetDuration(limit.budgetDuration)}` : "never resets")
2973
3000
  ));
2974
3001
  };
@@ -3176,6 +3203,15 @@ function budgetTone3(isOver, isNear) {
3176
3203
  if (isNear) return "warning";
3177
3204
  return "accent";
3178
3205
  }
3206
+ function visibleBudgetPct(spend, budget) {
3207
+ if (budget <= 0) return 0;
3208
+ return Math.min(spend / budget * 100, 100);
3209
+ }
3210
+ function budgetStatValue(hidden, budget) {
3211
+ if (hidden) return "Hidden";
3212
+ if (budget > 0) return fmtUsd2(budget);
3213
+ return "Unlimited";
3214
+ }
3179
3215
  var fmtUsd2, TeamCard, TeamUsage;
3180
3216
  var init_TeamUsage = __esm({
3181
3217
  "src/components/TeamUsage.tsx"() {
@@ -3185,13 +3221,15 @@ var init_TeamUsage = __esm({
3185
3221
  TeamCard = ({ team, usage, usageLoading, canManage, onEditTeam }) => {
3186
3222
  const [expanded, setExpanded] = useState6(false);
3187
3223
  const chart = useChartTheme();
3188
- const budget = team.max_budget ?? 0;
3189
- const spend = team.spend ?? 0;
3190
- const budgetPct = budget > 0 ? Math.min(spend / budget * 100, 100) : 0;
3191
- const isOver = budget > 0 && spend >= budget;
3192
- const isNear = budget > 0 && spend >= budget * 0.8 && !isOver;
3224
+ const hidden = team.budget_hidden === true;
3225
+ const budget = hidden ? 0 : team.max_budget ?? 0;
3226
+ const spend = hidden ? 0 : team.spend ?? 0;
3227
+ const budgetPct = hidden ? Math.min(100, Math.max(0, team.budget_pct ?? 0)) : visibleBudgetPct(spend, budget);
3228
+ const isOver = hidden ? team.budget_status === "over" : budget > 0 && spend >= budget;
3229
+ const isNear = hidden ? team.budget_status === "near" : budget > 0 && spend >= budget * 0.8 && !isOver;
3193
3230
  const dailyData = usage?.daily_usage?.map((d) => ({ date: d.date, spend: d.spend })) ?? [];
3194
3231
  const renderDailySpendSection = () => {
3232
+ if (hidden) return null;
3195
3233
  if (usageLoading) {
3196
3234
  return /* @__PURE__ */ React8.createElement(Box8, { display: "flex", justifyContent: "center", py: 3 }, /* @__PURE__ */ React8.createElement(CircularProgress5, { size: 22 }));
3197
3235
  }
@@ -3292,11 +3330,11 @@ var init_TeamUsage = __esm({
3292
3330
  },
3293
3331
  /* @__PURE__ */ React8.createElement(Stat, { label: "Members", value: team.members_with_roles?.length ?? "\u2014" }),
3294
3332
  /* @__PURE__ */ React8.createElement(Stat, { label: "Models", value: team.models?.length ? team.models.length : "All" }),
3295
- /* @__PURE__ */ React8.createElement(Stat, { label: "Budget", value: budget > 0 ? fmtUsd2(budget) : "Unlimited" }),
3296
- /* @__PURE__ */ React8.createElement(Stat, { label: "Spend", value: fmtUsd2(spend) }),
3333
+ /* @__PURE__ */ React8.createElement(Stat, { label: "Budget", value: budgetStatValue(hidden, budget) }),
3334
+ /* @__PURE__ */ React8.createElement(Stat, { label: "Spend", value: hidden ? "\u2014" : fmtUsd2(spend) }),
3297
3335
  /* @__PURE__ */ React8.createElement(Stat, { label: "TPM", value: team.tpm_limit && team.tpm_limit > 0 ? team.tpm_limit.toLocaleString() : "\u2014" }),
3298
3336
  /* @__PURE__ */ React8.createElement(Stat, { label: "RPM", value: team.rpm_limit && team.rpm_limit > 0 ? team.rpm_limit.toLocaleString() : "\u2014" })
3299
- ), budget > 0 && /* @__PURE__ */ React8.createElement(Box8, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ React8.createElement(Box8, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ React8.createElement(Typography8, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, fmtUsd2(spend), " of ", fmtUsd2(budget)), /* @__PURE__ */ React8.createElement(Typography8, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "%")), /* @__PURE__ */ React8.createElement(Meter, { value: budgetPct, tone: budgetTone3(isOver, isNear), height: 5 })), /* @__PURE__ */ React8.createElement(Collapse2, { in: expanded, unmountOnExit: true }, /* @__PURE__ */ React8.createElement(Divider3, { sx: { my: 2.5 } }), /* @__PURE__ */ React8.createElement(Box8, { mb: 2.5 }, sectionLabel("Models"), team.models?.length ? /* @__PURE__ */ React8.createElement(Box8, { display: "flex", gap: 0.5, flexWrap: "wrap" }, team.models.map((m) => /* @__PURE__ */ React8.createElement(TagChip, { key: m, label: m, title: m }))) : /* @__PURE__ */ React8.createElement(Typography8, { variant: "body2", color: "text.secondary" }, "All models allowed")), renderDailySpendSection(), /* @__PURE__ */ React8.createElement(Box8, null, sectionLabel("Members"), team.members_with_roles?.length ? /* @__PURE__ */ React8.createElement(
3337
+ ), hidden && /* @__PURE__ */ React8.createElement(Box8, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ React8.createElement(Box8, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ React8.createElement(Typography8, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "% used"), /* @__PURE__ */ React8.createElement(Typography8, { variant: "caption", color: "text.secondary" }, "Hidden by admin")), /* @__PURE__ */ React8.createElement(Meter, { value: budgetPct, tone: budgetTone3(isOver, isNear), height: 5 }), /* @__PURE__ */ React8.createElement(Typography8, { variant: "caption", color: "text.secondary", sx: { display: "block", mt: 0.75 } }, "Team budget is hidden \u2014 showing usage level only", team.budget_duration ? ` \xB7 resets every ${team.budget_duration}` : "", ".")), !hidden && budget > 0 && /* @__PURE__ */ React8.createElement(Box8, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ React8.createElement(Box8, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ React8.createElement(Typography8, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, fmtUsd2(spend), " of ", fmtUsd2(budget)), /* @__PURE__ */ React8.createElement(Typography8, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "%")), /* @__PURE__ */ React8.createElement(Meter, { value: budgetPct, tone: budgetTone3(isOver, isNear), height: 5 })), /* @__PURE__ */ React8.createElement(Collapse2, { in: expanded, unmountOnExit: true }, /* @__PURE__ */ React8.createElement(Divider3, { sx: { my: 2.5 } }), /* @__PURE__ */ React8.createElement(Box8, { mb: 2.5 }, sectionLabel("Models"), team.models?.length ? /* @__PURE__ */ React8.createElement(Box8, { display: "flex", gap: 0.5, flexWrap: "wrap" }, team.models.map((m) => /* @__PURE__ */ React8.createElement(TagChip, { key: m, label: m, title: m }))) : /* @__PURE__ */ React8.createElement(Typography8, { variant: "body2", color: "text.secondary" }, "All models allowed")), renderDailySpendSection(), /* @__PURE__ */ React8.createElement(Box8, null, sectionLabel("Members"), team.members_with_roles?.length ? /* @__PURE__ */ React8.createElement(
3300
3338
  TableContainer4,
3301
3339
  {
3302
3340
  component: Paper6,
@@ -3625,7 +3663,7 @@ var init_ModelsTable = __esm({
3625
3663
  });
3626
3664
 
3627
3665
  // src/components/AuditLog.tsx
3628
- import React10, { useState as useState8, useCallback as useCallback2 } from "react";
3666
+ import React10, { useState as useState8, useMemo as useMemo8 } from "react";
3629
3667
  import Box10 from "@mui/material/Box";
3630
3668
  import Typography10 from "@mui/material/Typography";
3631
3669
  import Table6 from "@mui/material/Table";
@@ -3764,10 +3802,10 @@ var init_AuditLog = __esm({
3764
3802
  const [page, setPage] = useState8(0);
3765
3803
  const [pageSize, setPageSize] = useState8(25);
3766
3804
  const [filters, setFilters] = useState8({});
3767
- const fetchParams = useCallback2(
3805
+ const fetchParams = useMemo8(
3768
3806
  () => ({ page: page + 1, page_size: pageSize, ...filters }),
3769
3807
  [page, pageSize, filters]
3770
- )();
3808
+ );
3771
3809
  const { value, loading, error } = useAsync2(
3772
3810
  () => api.getAuditLogs(fetchParams),
3773
3811
  [api, fetchParams]
@@ -3888,7 +3926,7 @@ var LiteLLMPage_exports = {};
3888
3926
  __export(LiteLLMPage_exports, {
3889
3927
  LiteLLMPage: () => LiteLLMPage
3890
3928
  });
3891
- import React11, { useState as useState9, useCallback as useCallback3, useMemo as useMemo8 } from "react";
3929
+ import React11, { useState as useState9, useCallback as useCallback2, useMemo as useMemo9 } from "react";
3892
3930
  import Box11 from "@mui/material/Box";
3893
3931
  import Snackbar2 from "@mui/material/Snackbar";
3894
3932
  import Alert6 from "@mui/material/Alert";
@@ -3949,7 +3987,7 @@ var init_LiteLLMPage = __esm({
3949
3987
  const t = searchParams.get("tab");
3950
3988
  return isPageTab(t) ? t : "overview";
3951
3989
  });
3952
- const selectTab = useCallback3(
3990
+ const selectTab = useCallback2(
3953
3991
  (tab) => {
3954
3992
  setActiveTab(tab);
3955
3993
  setSearchParams(
@@ -4011,7 +4049,7 @@ var init_LiteLLMPage = __esm({
4011
4049
  async () => objectPermsEnabled ? api.getMcpServers().catch(() => []) : [],
4012
4050
  [api, objectPermsEnabled]
4013
4051
  );
4014
- const teams = useMemo8(() => {
4052
+ const teams = useMemo9(() => {
4015
4053
  if (!allTeams?.length) return [];
4016
4054
  if (!userInfo) return allTeams;
4017
4055
  const userId = userInfo.user_id;
@@ -4028,7 +4066,7 @@ var init_LiteLLMPage = __esm({
4028
4066
  const endDate = dateRange.end.toISOString().split("T")[0];
4029
4067
  return api.getUsage(startDate, endDate);
4030
4068
  }, [api, dateRange]);
4031
- const handleDateRangeChange = useCallback3((range, preset) => {
4069
+ const handleDateRangeChange = useCallback2((range, preset) => {
4032
4070
  setDateRange(range);
4033
4071
  if (preset) {
4034
4072
  setCurrentPreset(preset);
@@ -4036,7 +4074,7 @@ var init_LiteLLMPage = __esm({
4036
4074
  setTeamUsageCache({});
4037
4075
  setTeamUsageLoading({});
4038
4076
  }, [setDateRange, setCurrentPreset]);
4039
- const loadTeamUsage = useCallback3(async (teamId) => {
4077
+ const loadTeamUsage = useCallback2(async (teamId) => {
4040
4078
  if (teamUsageCache[teamId] !== void 0 || teamUsageLoading[teamId]) return;
4041
4079
  setTeamUsageLoading((prev) => ({ ...prev, [teamId]: true }));
4042
4080
  try {
@@ -4050,7 +4088,7 @@ var init_LiteLLMPage = __esm({
4050
4088
  setTeamUsageLoading((prev) => ({ ...prev, [teamId]: false }));
4051
4089
  }
4052
4090
  }, [api, dateRange, teamUsageCache, teamUsageLoading]);
4053
- const allowedModels = useMemo8(() => {
4091
+ const allowedModels = useMemo9(() => {
4054
4092
  if (!allModels?.length) return [];
4055
4093
  const userModels = userInfo?.models;
4056
4094
  const teamModels = teams?.flatMap((t) => t.models ?? []);
@@ -4063,7 +4101,7 @@ var init_LiteLLMPage = __esm({
4063
4101
  ]);
4064
4102
  return allModels.filter((m) => allowed.has(m.model_name));
4065
4103
  }, [allModels, userInfo, teams]);
4066
- const handleGenerateKey = useCallback3(
4104
+ const handleGenerateKey = useCallback2(
4067
4105
  async (request) => {
4068
4106
  try {
4069
4107
  const response = await api.generateKey(request);
@@ -4077,7 +4115,7 @@ var init_LiteLLMPage = __esm({
4077
4115
  },
4078
4116
  [api, refreshKeys]
4079
4117
  );
4080
- const handleUpdateKey = useCallback3(
4118
+ const handleUpdateKey = useCallback2(
4081
4119
  async (keyId, request) => {
4082
4120
  try {
4083
4121
  await api.updateKey(keyId, request);
@@ -4090,7 +4128,7 @@ var init_LiteLLMPage = __esm({
4090
4128
  },
4091
4129
  [api, refreshKeys]
4092
4130
  );
4093
- const handleBlockKey = useCallback3(
4131
+ const handleBlockKey = useCallback2(
4094
4132
  async (keyId) => {
4095
4133
  try {
4096
4134
  await api.blockKey(keyId);
@@ -4102,7 +4140,7 @@ var init_LiteLLMPage = __esm({
4102
4140
  },
4103
4141
  [api, refreshKeys]
4104
4142
  );
4105
- const handleUnblockKey = useCallback3(
4143
+ const handleUnblockKey = useCallback2(
4106
4144
  async (keyId) => {
4107
4145
  try {
4108
4146
  await api.unblockKey(keyId);
@@ -4114,7 +4152,7 @@ var init_LiteLLMPage = __esm({
4114
4152
  },
4115
4153
  [api, refreshKeys]
4116
4154
  );
4117
- const handleResetKeySpend = useCallback3(
4155
+ const handleResetKeySpend = useCallback2(
4118
4156
  async (keyId) => {
4119
4157
  try {
4120
4158
  await api.resetKeySpend(keyId);
@@ -4126,7 +4164,7 @@ var init_LiteLLMPage = __esm({
4126
4164
  },
4127
4165
  [api, refreshKeys]
4128
4166
  );
4129
- const handleDeleteKey = useCallback3(
4167
+ const handleDeleteKey = useCallback2(
4130
4168
  async (keyId) => {
4131
4169
  try {
4132
4170
  await api.deleteKey(keyId);
@@ -4143,7 +4181,7 @@ var init_LiteLLMPage = __esm({
4143
4181
  },
4144
4182
  [api, refreshKeys]
4145
4183
  );
4146
- const handlePruneExpiredKeys = useCallback3(
4184
+ const handlePruneExpiredKeys = useCallback2(
4147
4185
  async () => {
4148
4186
  try {
4149
4187
  const result = await api.pruneExpiredKeys();