@acarmisc/backstage-plugin-litellm 0.21.1 → 0.21.3

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.cjs.js CHANGED
@@ -2855,7 +2855,7 @@ function levelToneColor(tone, theme) {
2855
2855
  return theme.palette.primary.main;
2856
2856
  }
2857
2857
  }
2858
- var import_react7, import_Paper5, import_Box7, import_Typography7, import_CircularProgress4, import_Alert3, import_Collapse, import_IconButton4, import_icons_material5, import_styles4, import_core_plugin_api3, LevelFrame, EmptyLimitCard, LimitCard, CLOSEST_LEVEL_LABEL, TaggedLimit, FullBody, CompactBody, LiteLLMBudgetWidget;
2858
+ var import_react7, import_Paper5, import_Box7, import_Typography7, import_CircularProgress4, import_Alert3, import_Collapse, import_IconButton4, import_icons_material5, import_styles4, import_core_plugin_api3, import_core_components, LevelFrame, EmptyLimitCard, LimitCard, CLOSEST_LEVEL_LABEL, KEYS_PATH, MoreKeysNote, HierarchyNote, TaggedLimit, FullBody, CompactBody, LiteLLMBudgetWidget;
2859
2859
  var init_LiteLLMBudgetWidget = __esm({
2860
2860
  "src/components/LiteLLMBudgetWidget.tsx"() {
2861
2861
  "use strict";
@@ -2870,6 +2870,7 @@ var init_LiteLLMBudgetWidget = __esm({
2870
2870
  import_icons_material5 = require("@mui/icons-material");
2871
2871
  import_styles4 = require("@mui/material/styles");
2872
2872
  import_core_plugin_api3 = require("@backstage/core-plugin-api");
2873
+ import_core_components = require("@backstage/core-components");
2873
2874
  init_api();
2874
2875
  init_format();
2875
2876
  init_ui();
@@ -2983,6 +2984,21 @@ var init_LiteLLMBudgetWidget = __esm({
2983
2984
  user: "personal",
2984
2985
  team: "team"
2985
2986
  };
2987
+ KEYS_PATH = "/litellm?tab=keys";
2988
+ MoreKeysNote = ({ count }) => /* @__PURE__ */ import_react7.default.createElement(import_core_components.Link, { to: KEYS_PATH, variant: "caption" }, "+", count, " more budgeted key", count > 1 ? "s" : "", " further from the cap \u2192");
2989
+ HierarchyNote = ({ withReset }) => /* @__PURE__ */ import_react7.default.createElement(
2990
+ import_Box7.default,
2991
+ {
2992
+ sx: (theme) => ({
2993
+ px: 1.5,
2994
+ py: 1.25,
2995
+ borderRadius: 1.5,
2996
+ border: "1px dashed",
2997
+ borderColor: (0, import_styles4.alpha)(theme.palette.text.primary, 0.18)
2998
+ })
2999
+ },
3000
+ /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary", display: "block" }, /* @__PURE__ */ import_react7.default.createElement("b", null, "Order:"), " key \u2192 personal \u2192 team \u2192 global. The first cap you reach blocks the request; a key that belongs to a team uses the team's cap, not your personal one.", withReset && " A cap with a reset window drops to $0 when the window closes; without one it never resets.")
3001
+ );
2986
3002
  TaggedLimit = ({ limit }) => {
2987
3003
  const tone = budgetTone2(limit.pct);
2988
3004
  return /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, null, /* @__PURE__ */ import_react7.default.createElement(
@@ -3012,7 +3028,7 @@ var init_LiteLLMBudgetWidget = __esm({
3012
3028
  },
3013
3029
  !hasBudgetedKeys && /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "No key has a budget, so no key-level cap applies."),
3014
3030
  summary.keys.map((k) => /* @__PURE__ */ import_react7.default.createElement(LimitCard, { key: k.sublabel ?? k.label, limit: k })),
3015
- summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary" }, "+", summary.hiddenBudgetedKeys, " more budgeted key", summary.hiddenBudgetedKeys > 1 ? "s" : "", " further from the cap")
3031
+ summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react7.default.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys })
3016
3032
  ), /* @__PURE__ */ import_react7.default.createElement(
3017
3033
  LevelFrame,
3018
3034
  {
@@ -3022,27 +3038,14 @@ var init_LiteLLMBudgetWidget = __esm({
3022
3038
  note: "skipped for team-bound keys"
3023
3039
  },
3024
3040
  summary.user ? /* @__PURE__ */ import_react7.default.createElement(LimitCard, { limit: summary.user }) : /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "No personal budget is set on your account.")
3025
- ), /* @__PURE__ */ import_react7.default.createElement(LevelFrame, { rank: 3, name: "Team", tagline: "shared cap for all keys in a team (if any)" }, summary.teams.length > 0 ? summary.teams.map((t) => /* @__PURE__ */ import_react7.default.createElement(LimitCard, { key: t.sublabel ?? t.label, limit: t })) : /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "No team you belong to has a budget.")), /* @__PURE__ */ import_react7.default.createElement(LevelFrame, { rank: 4, name: "Global", tagline: "proxy-wide cap set by your admin", isLast: true }, /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "Configured by your admin in the proxy config \u2014 it isn't visible from this page. When set, it limits spend across every request on the proxy.")), /* @__PURE__ */ import_react7.default.createElement(
3026
- import_Box7.default,
3027
- {
3028
- sx: (theme) => ({
3029
- mt: 2,
3030
- px: 1.5,
3031
- py: 1.25,
3032
- borderRadius: 1.5,
3033
- border: "1px dashed",
3034
- borderColor: (0, import_styles4.alpha)(theme.palette.text.primary, 0.18)
3035
- })
3036
- },
3037
- /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary", display: "block" }, "The first cap a request runs into is the one that stops it. A limit with a reset window (e.g. daily or every 30 days) clears its spend to $0 when the window closes; without a window it never resets.")
3038
- ));
3041
+ ), /* @__PURE__ */ import_react7.default.createElement(LevelFrame, { rank: 3, name: "Team", tagline: "shared cap for all keys in a team (if any)" }, summary.teams.length > 0 ? summary.teams.map((t) => /* @__PURE__ */ import_react7.default.createElement(LimitCard, { key: t.sublabel ?? t.label, limit: t })) : /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "No team you belong to has a budget.")), /* @__PURE__ */ import_react7.default.createElement(LevelFrame, { rank: 4, name: "Global", tagline: "proxy-wide cap set by your admin", isLast: true }, /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "Configured by your admin in the proxy config \u2014 it isn't visible from this page. When set, it limits spend across every request on the proxy.")), /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { mt: 2 } }, /* @__PURE__ */ import_react7.default.createElement(HierarchyNote, { withReset: true })));
3039
3042
  };
3040
3043
  CompactBody = ({ summary }) => {
3041
3044
  const { count } = budgetHeadline(summary);
3042
3045
  if (count === 0) {
3043
3046
  return /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, "No budget limits apply to you right now.");
3044
3047
  }
3045
- return /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, summary.keys.map((k) => /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { key: k.sublabel ?? k.label, limit: k })), summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary" }, "+", summary.hiddenBudgetedKeys, " more budgeted key", summary.hiddenBudgetedKeys > 1 ? "s" : "", " further from the cap"), summary.user && /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { limit: summary.user }), summary.teams.map((t) => /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { key: t.sublabel ?? t.label, limit: t })));
3048
+ return /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, /* @__PURE__ */ import_react7.default.createElement(HierarchyNote, null), summary.keys.map((k) => /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { key: k.sublabel ?? k.label, limit: k })), summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react7.default.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys }), summary.user && /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { limit: summary.user }), summary.teams.map((t) => /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { key: t.sublabel ?? t.label, limit: t })));
3046
3049
  };
3047
3050
  LiteLLMBudgetWidget = ({
3048
3051
  title = "Budget Policy",
@@ -3398,7 +3401,7 @@ function fmtTokens(n) {
3398
3401
  if (n >= 1e3) return `${(n / 1e3).toFixed(0)}K`;
3399
3402
  return String(n);
3400
3403
  }
3401
- var import_react9, import_Box9, import_Table5, import_TableBody5, import_TableCell5, import_TableContainer5, import_TableHead5, import_TableRow5, import_Typography9, import_MenuItem4, import_Select, import_FormControl, import_InputLabel, import_TextField5, import_InputAdornment2, import_icons_material7, import_ContentCopy, import_Tooltip, import_Snackbar, import_Alert4, import_styles6, ALL_PROXY_MODELS2, ModelsTable;
3404
+ var import_react9, import_Box9, import_Table5, import_TableBody5, import_TableCell5, import_TableContainer5, import_TableHead5, import_TableRow5, import_TableSortLabel2, import_Typography9, import_MenuItem4, import_Select, import_FormControl, import_InputLabel, import_TextField5, import_InputAdornment2, import_icons_material7, import_ContentCopy, import_Tooltip, import_Snackbar, import_Alert4, import_styles6, ALL_PROXY_MODELS2, ModelsTable;
3402
3405
  var init_ModelsTable = __esm({
3403
3406
  "src/components/ModelsTable.tsx"() {
3404
3407
  "use strict";
@@ -3410,6 +3413,7 @@ var init_ModelsTable = __esm({
3410
3413
  import_TableContainer5 = __toESM(require("@mui/material/TableContainer"));
3411
3414
  import_TableHead5 = __toESM(require("@mui/material/TableHead"));
3412
3415
  import_TableRow5 = __toESM(require("@mui/material/TableRow"));
3416
+ import_TableSortLabel2 = __toESM(require("@mui/material/TableSortLabel"));
3413
3417
  import_Typography9 = __toESM(require("@mui/material/Typography"));
3414
3418
  import_MenuItem4 = __toESM(require("@mui/material/MenuItem"));
3415
3419
  import_Select = __toESM(require("@mui/material/Select"));
@@ -3430,6 +3434,8 @@ var init_ModelsTable = __esm({
3430
3434
  const [selectedTeamId, setSelectedTeamId] = (0, import_react9.useState)("");
3431
3435
  const [filterText, setFilterText] = (0, import_react9.useState)("");
3432
3436
  const [copiedSnackbar, setCopiedSnackbar] = (0, import_react9.useState)(false);
3437
+ const [sortKey, setSortKey] = (0, import_react9.useState)("model_name");
3438
+ const [sortDirection, setSortDirection] = (0, import_react9.useState)("asc");
3433
3439
  const selectedTeam = (0, import_react9.useMemo)(
3434
3440
  () => teams.find((t) => t.team_id === selectedTeamId) ?? null,
3435
3441
  [teams, selectedTeamId]
@@ -3440,14 +3446,62 @@ var init_ModelsTable = __esm({
3440
3446
  }, [allModels, selectedTeam]);
3441
3447
  const filteredModels = (0, import_react9.useMemo)(() => {
3442
3448
  const q = filterText.trim().toLowerCase();
3443
- if (!q) return teamModels;
3444
- return teamModels.filter(
3445
- (model) => model.model_name.toLowerCase().includes(q) || (model.access_groups || []).some((group) => group.toLowerCase().includes(q))
3446
- );
3447
- }, [teamModels, filterText]);
3449
+ let models = teamModels;
3450
+ if (q) {
3451
+ models = teamModels.filter(
3452
+ (model) => model.model_name.toLowerCase().includes(q) || (model.access_groups || []).some((group) => group.toLowerCase().includes(q))
3453
+ );
3454
+ }
3455
+ return [...models].sort((a, b) => {
3456
+ let aVal;
3457
+ let bVal;
3458
+ switch (sortKey) {
3459
+ case "model_name":
3460
+ aVal = a.model_name;
3461
+ bVal = b.model_name;
3462
+ break;
3463
+ case "mode":
3464
+ aVal = a.mode;
3465
+ bVal = b.mode;
3466
+ break;
3467
+ case "input_cost_per_token":
3468
+ aVal = a.input_cost_per_token ?? 0;
3469
+ bVal = b.input_cost_per_token ?? 0;
3470
+ break;
3471
+ case "output_cost_per_token":
3472
+ aVal = a.output_cost_per_token ?? 0;
3473
+ bVal = b.output_cost_per_token ?? 0;
3474
+ break;
3475
+ case "max_input_tokens":
3476
+ aVal = a.max_input_tokens ?? 0;
3477
+ bVal = b.max_input_tokens ?? 0;
3478
+ break;
3479
+ case "max_output_tokens":
3480
+ aVal = a.max_output_tokens ?? 0;
3481
+ bVal = b.max_output_tokens ?? 0;
3482
+ break;
3483
+ default:
3484
+ return 0;
3485
+ }
3486
+ if (aVal === void 0 || aVal === null) aVal = "";
3487
+ if (bVal === void 0 || bVal === null) bVal = "";
3488
+ if (typeof aVal === "string" && typeof bVal === "string") {
3489
+ return sortDirection === "asc" ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
3490
+ }
3491
+ return sortDirection === "asc" ? aVal - bVal : bVal - aVal;
3492
+ });
3493
+ }, [teamModels, filterText, sortKey, sortDirection]);
3448
3494
  const handleCopyModelId = (0, import_react9.useCallback)((modelId) => {
3449
3495
  navigator.clipboard.writeText(modelId).then(() => setCopiedSnackbar(true));
3450
3496
  }, []);
3497
+ const handleSort = (0, import_react9.useCallback)((key) => {
3498
+ if (sortKey === key) {
3499
+ setSortDirection((prev) => prev === "asc" ? "desc" : "asc");
3500
+ } else {
3501
+ setSortKey(key);
3502
+ setSortDirection("asc");
3503
+ }
3504
+ }, [sortKey]);
3451
3505
  const modeColor = (mode) => {
3452
3506
  switch (mode) {
3453
3507
  case "chat":
@@ -3513,7 +3567,7 @@ var init_ModelsTable = __esm({
3513
3567
  hint: "Try a different search term"
3514
3568
  }
3515
3569
  ),
3516
- !loading && filteredModels.length > 0 && /* @__PURE__ */ import_react9.default.createElement(import_TableContainer5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_Table5.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react9.default.createElement(import_TableHead5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableRow5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, "Model ID"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, "Mode"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { align: "right" }, "Input Cost"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { align: "right" }, "Output Cost"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { align: "right" }, "Max Input"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { align: "right" }, "Max Output"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, "Capabilities"))), /* @__PURE__ */ import_react9.default.createElement(import_TableBody5.default, null, filteredModels.map((m) => /* @__PURE__ */ import_react9.default.createElement(import_TableRow5.default, { key: m.model_name, hover: true }, /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ import_react9.default.createElement(import_Tooltip.default, { title: m.model_name, placement: "top" }, /* @__PURE__ */ import_react9.default.createElement(
3570
+ !loading && filteredModels.length > 0 && /* @__PURE__ */ import_react9.default.createElement(import_TableContainer5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_Table5.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react9.default.createElement(import_TableHead5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableRow5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { sortDirection: sortKey === "model_name" ? sortDirection : false }, /* @__PURE__ */ import_react9.default.createElement(import_TableSortLabel2.default, { active: sortKey === "model_name", direction: sortKey === "model_name" ? sortDirection : "asc", onClick: () => handleSort("model_name") }, "Model ID")), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { sortDirection: sortKey === "mode" ? sortDirection : false }, /* @__PURE__ */ import_react9.default.createElement(import_TableSortLabel2.default, { active: sortKey === "mode", direction: sortKey === "mode" ? sortDirection : "asc", onClick: () => handleSort("mode") }, "Mode")), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "input_cost_per_token" ? sortDirection : false }, /* @__PURE__ */ import_react9.default.createElement(import_TableSortLabel2.default, { active: sortKey === "input_cost_per_token", direction: sortKey === "input_cost_per_token" ? sortDirection : "asc", onClick: () => handleSort("input_cost_per_token") }, "Input Cost")), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "output_cost_per_token" ? sortDirection : false }, /* @__PURE__ */ import_react9.default.createElement(import_TableSortLabel2.default, { active: sortKey === "output_cost_per_token", direction: sortKey === "output_cost_per_token" ? sortDirection : "asc", onClick: () => handleSort("output_cost_per_token") }, "Output Cost")), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "max_input_tokens" ? sortDirection : false }, /* @__PURE__ */ import_react9.default.createElement(import_TableSortLabel2.default, { active: sortKey === "max_input_tokens", direction: sortKey === "max_input_tokens" ? sortDirection : "asc", onClick: () => handleSort("max_input_tokens") }, "Max Input")), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "max_output_tokens" ? sortDirection : false }, /* @__PURE__ */ import_react9.default.createElement(import_TableSortLabel2.default, { active: sortKey === "max_output_tokens", direction: sortKey === "max_output_tokens" ? sortDirection : "asc", onClick: () => handleSort("max_output_tokens") }, "Max Output")), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, "Capabilities"))), /* @__PURE__ */ import_react9.default.createElement(import_TableBody5.default, null, filteredModels.map((m) => /* @__PURE__ */ import_react9.default.createElement(import_TableRow5.default, { key: m.model_name, hover: true }, /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ import_react9.default.createElement(import_Tooltip.default, { title: m.model_name, placement: "top" }, /* @__PURE__ */ import_react9.default.createElement(
3517
3571
  "span",
3518
3572
  {
3519
3573
  role: "button",
@@ -3847,7 +3901,7 @@ function initDateRange() {
3847
3901
  else start.setDate(start.getDate() - 7);
3848
3902
  return { start, end };
3849
3903
  }
3850
- var import_react11, import_Box11, import_Snackbar2, import_Alert6, import_CircularProgress6, import_Typography11, import_Paper7, import_Tabs2, import_Tab2, import_Grid2, import_react_use3, import_core_plugin_api4, import_plugin_permission_react, PERIOD_LS_KEY2, LiteLLMPage;
3904
+ var import_react11, import_Box11, import_Snackbar2, import_Alert6, import_CircularProgress6, import_Typography11, import_Paper7, import_Tabs2, import_Tab2, import_Grid2, import_react_router_dom, import_react_use3, import_core_plugin_api4, import_plugin_permission_react, PERIOD_LS_KEY2, PAGE_TABS, isPageTab, LiteLLMPage;
3851
3905
  var init_LiteLLMPage = __esm({
3852
3906
  "src/components/LiteLLMPage.tsx"() {
3853
3907
  "use strict";
@@ -3861,6 +3915,7 @@ var init_LiteLLMPage = __esm({
3861
3915
  import_Tabs2 = __toESM(require("@mui/material/Tabs"));
3862
3916
  import_Tab2 = __toESM(require("@mui/material/Tab"));
3863
3917
  import_Grid2 = __toESM(require("@mui/material/Grid"));
3918
+ import_react_router_dom = require("react-router-dom");
3864
3919
  import_react_use3 = require("react-use");
3865
3920
  import_core_plugin_api4 = require("@backstage/core-plugin-api");
3866
3921
  import_plugin_permission_react = require("@backstage/plugin-permission-react");
@@ -3876,6 +3931,8 @@ var init_LiteLLMPage = __esm({
3876
3931
  init_api();
3877
3932
  init_permissions();
3878
3933
  PERIOD_LS_KEY2 = "litellm_usage_period";
3934
+ PAGE_TABS = ["overview", "keys", "teams", "models", "audit"];
3935
+ isPageTab = (v) => !!v && PAGE_TABS.includes(v);
3879
3936
  LiteLLMPage = () => {
3880
3937
  const api = (0, import_core_plugin_api4.useApi)(liteLlmApiRef);
3881
3938
  const [dateRange, setDateRange] = (0, import_react11.useState)(initDateRange);
@@ -3886,7 +3943,25 @@ var init_LiteLLMPage = __esm({
3886
3943
  return "7d";
3887
3944
  }
3888
3945
  });
3889
- const [activeTab, setActiveTab] = (0, import_react11.useState)("overview");
3946
+ const [searchParams, setSearchParams] = (0, import_react_router_dom.useSearchParams)();
3947
+ const [activeTab, setActiveTab] = (0, import_react11.useState)(() => {
3948
+ const t = searchParams.get("tab");
3949
+ return isPageTab(t) ? t : "overview";
3950
+ });
3951
+ const selectTab = (0, import_react11.useCallback)(
3952
+ (tab) => {
3953
+ setActiveTab(tab);
3954
+ setSearchParams(
3955
+ (prev) => {
3956
+ const next = new URLSearchParams(prev);
3957
+ next.set("tab", tab);
3958
+ return next;
3959
+ },
3960
+ { replace: true }
3961
+ );
3962
+ },
3963
+ [setSearchParams]
3964
+ );
3890
3965
  const [snackbar, setSnackbar] = (0, import_react11.useState)(null);
3891
3966
  const [generateDialogOpen, setGenerateDialogOpen] = (0, import_react11.useState)(false);
3892
3967
  const [manageTeam, setManageTeam] = (0, import_react11.useState)(null);
@@ -4093,7 +4168,7 @@ var init_LiteLLMPage = __esm({
4093
4168
  import_Tabs2.default,
4094
4169
  {
4095
4170
  value: activeTab,
4096
- onChange: (_, v) => setActiveTab(v),
4171
+ onChange: (_, v) => selectTab(v),
4097
4172
  variant: "scrollable",
4098
4173
  scrollButtons: "auto",
4099
4174
  sx: {