@acarmisc/backstage-plugin-litellm 0.15.0 → 0.15.2
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 +61 -18
- package/dist/index.cjs.js.map +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +62 -19
- package/dist/index.esm.js.map +3 -3
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -913,7 +913,25 @@ function formatContextWindow(maxInput, maxOutput) {
|
|
|
913
913
|
if (outPart) return `ctx ${outPart} out`;
|
|
914
914
|
return null;
|
|
915
915
|
}
|
|
916
|
-
|
|
916
|
+
function compareKeys(a, b, sortKey) {
|
|
917
|
+
switch (sortKey) {
|
|
918
|
+
case "alias":
|
|
919
|
+
return (a.key_alias ?? "").localeCompare(b.key_alias ?? "");
|
|
920
|
+
case "created":
|
|
921
|
+
return a.created_at.localeCompare(b.created_at);
|
|
922
|
+
case "expires":
|
|
923
|
+
return (a.expires_at ?? "").localeCompare(b.expires_at ?? "");
|
|
924
|
+
case "budget":
|
|
925
|
+
return (a.max_budget ?? Infinity) - (b.max_budget ?? Infinity);
|
|
926
|
+
case "limits":
|
|
927
|
+
return (a.tpm_limit ?? Infinity) - (b.tpm_limit ?? Infinity) || (a.rpm_limit ?? Infinity) - (b.rpm_limit ?? Infinity);
|
|
928
|
+
case "models":
|
|
929
|
+
return (a.models ?? []).join(",").localeCompare((b.models ?? []).join(","));
|
|
930
|
+
default:
|
|
931
|
+
return 0;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
var import_react3, import_Table, import_TableBody, import_TableCell, import_TableContainer, import_TableHead, import_TableRow, import_TableSortLabel, import_Button2, import_IconButton, import_Box3, import_Typography3, import_Dialog, import_DialogTitle, import_DialogContent, import_DialogActions, import_TextField, import_CircularProgress, import_Autocomplete, import_Skeleton2, import_InputAdornment, import_styles3, import_icons_material2, maskKey, shortKeyId, formatDate, keyToEditForm, KeysTable;
|
|
917
935
|
var init_KeysTable = __esm({
|
|
918
936
|
"src/components/KeysTable.tsx"() {
|
|
919
937
|
"use strict";
|
|
@@ -924,6 +942,7 @@ var init_KeysTable = __esm({
|
|
|
924
942
|
import_TableContainer = __toESM(require("@mui/material/TableContainer"));
|
|
925
943
|
import_TableHead = __toESM(require("@mui/material/TableHead"));
|
|
926
944
|
import_TableRow = __toESM(require("@mui/material/TableRow"));
|
|
945
|
+
import_TableSortLabel = __toESM(require("@mui/material/TableSortLabel"));
|
|
927
946
|
import_Button2 = __toESM(require("@mui/material/Button"));
|
|
928
947
|
import_IconButton = __toESM(require("@mui/material/IconButton"));
|
|
929
948
|
import_Box3 = __toESM(require("@mui/material/Box"));
|
|
@@ -985,13 +1004,29 @@ var init_KeysTable = __esm({
|
|
|
985
1004
|
const [resetSpendConfirm, setResetSpendConfirm] = (0, import_react3.useState)(false);
|
|
986
1005
|
const [resetSpendSubmitting, setResetSpendSubmitting] = (0, import_react3.useState)(false);
|
|
987
1006
|
const [filterText, setFilterText] = (0, import_react3.useState)("");
|
|
1007
|
+
const [sortKey, setSortKey] = (0, import_react3.useState)("created");
|
|
1008
|
+
const [sortDirection, setSortDirection] = (0, import_react3.useState)("desc");
|
|
1009
|
+
const handleSort = (nextSortKey) => {
|
|
1010
|
+
if (sortKey === nextSortKey) {
|
|
1011
|
+
setSortDirection((current) => current === "asc" ? "desc" : "asc");
|
|
1012
|
+
} else {
|
|
1013
|
+
setSortKey(nextSortKey);
|
|
1014
|
+
setSortDirection("asc");
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
988
1017
|
const filteredKeys = (0, import_react3.useMemo)(() => {
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1018
|
+
let result = keys;
|
|
1019
|
+
if (filterText.trim()) {
|
|
1020
|
+
const q = filterText.toLowerCase();
|
|
1021
|
+
result = keys.filter(
|
|
1022
|
+
(k) => (k.key_alias ?? "").toLowerCase().includes(q) || k.models?.some((m) => m.toLowerCase().includes(q))
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
return [...result].sort((a, b) => {
|
|
1026
|
+
const comparison = compareKeys(a, b, sortKey);
|
|
1027
|
+
return sortDirection === "asc" ? comparison : -comparison;
|
|
1028
|
+
});
|
|
1029
|
+
}, [keys, filterText, sortKey, sortDirection]);
|
|
995
1030
|
const editSelectedModels = models.filter((m) => (editForm.models || []).includes(m.model_name));
|
|
996
1031
|
const handleOpenEdit = (k) => {
|
|
997
1032
|
setEditingKey(k);
|
|
@@ -1121,7 +1156,7 @@ var init_KeysTable = __esm({
|
|
|
1121
1156
|
"& td": { color: theme.palette.text.secondary }
|
|
1122
1157
|
}) : void 0
|
|
1123
1158
|
},
|
|
1124
|
-
/* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Box3.default, { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { variant: "body2"
|
|
1159
|
+
/* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Box3.default, { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { variant: "body2" }, key.key_alias || "\u2014"), key.blocked && /* @__PURE__ */ import_react3.default.createElement(StatusPill, { label: "Blocked", tone: "danger" }))),
|
|
1125
1160
|
/* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Box3.default, { display: "flex", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ import_react3.default.createElement(
|
|
1126
1161
|
import_Typography3.default,
|
|
1127
1162
|
{
|
|
@@ -1203,7 +1238,8 @@ var init_KeysTable = __esm({
|
|
|
1203
1238
|
import_TextField.default,
|
|
1204
1239
|
{
|
|
1205
1240
|
size: "small",
|
|
1206
|
-
|
|
1241
|
+
label: "Search alias or model",
|
|
1242
|
+
placeholder: "Search alias or model\u2026",
|
|
1207
1243
|
value: filterText,
|
|
1208
1244
|
onChange: (e) => setFilterText(e.target.value),
|
|
1209
1245
|
sx: { minWidth: 240 },
|
|
@@ -1243,7 +1279,7 @@ var init_KeysTable = __esm({
|
|
|
1243
1279
|
"Generate New Key"
|
|
1244
1280
|
))
|
|
1245
1281
|
},
|
|
1246
|
-
/* @__PURE__ */ import_react3.default.createElement(import_TableContainer.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Table.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react3.default.createElement(import_TableHead.default, null, /* @__PURE__ */ import_react3.default.createElement(import_TableRow.default, null, /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default,
|
|
1282
|
+
/* @__PURE__ */ import_react3.default.createElement(import_TableContainer.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Table.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react3.default.createElement(import_TableHead.default, null, /* @__PURE__ */ import_react3.default.createElement(import_TableRow.default, null, /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "alias" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "alias", direction: sortKey === "alias" ? sortDirection : "asc", onClick: () => handleSort("alias") }, "Alias")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, "Key ID"), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "created" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "created", direction: sortKey === "created" ? sortDirection : "asc", onClick: () => handleSort("created") }, "Created")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "expires" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "expires", direction: sortKey === "expires" ? sortDirection : "asc", onClick: () => handleSort("expires") }, "Expires")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "budget" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "budget", direction: sortKey === "budget" ? sortDirection : "asc", onClick: () => handleSort("budget") }, "Budget")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "limits" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "limits", direction: sortKey === "limits" ? sortDirection : "asc", onClick: () => handleSort("limits") }, "TPM / RPM")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "models" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "models", direction: sortKey === "models" ? sortDirection : "asc", onClick: () => handleSort("models") }, "Models")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { align: "right" }, "Actions"))), /* @__PURE__ */ import_react3.default.createElement(import_TableBody.default, null, renderTableBody())))
|
|
1247
1283
|
), /* @__PURE__ */ import_react3.default.createElement(import_Dialog.default, { open: !!editingKey, onClose: handleCloseEdit, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ import_react3.default.createElement(import_DialogTitle.default, null, "Edit Key"), /* @__PURE__ */ import_react3.default.createElement(import_DialogContent.default, null, editingKey && /* @__PURE__ */ import_react3.default.createElement(import_Box3.default, { display: "flex", flexDirection: "column", gap: 2, mt: 1 }, /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary" }, /* @__PURE__ */ import_react3.default.createElement("code", { style: { fontFamily: "monospace", color: "inherit" } }, maskKey(editingKey.key))), /* @__PURE__ */ import_react3.default.createElement(
|
|
1248
1284
|
import_TextField.default,
|
|
1249
1285
|
{
|
|
@@ -1467,7 +1503,7 @@ function formatContextWindow2(maxInput, maxOutput) {
|
|
|
1467
1503
|
if (outPart) return `ctx ${outPart} out`;
|
|
1468
1504
|
return null;
|
|
1469
1505
|
}
|
|
1470
|
-
var import_react4, import_Box4, import_Typography4, import_Dialog2, import_DialogTitle2, import_DialogContent2, import_DialogActions2, import_TextField2, import_MenuItem, import_Button3, import_IconButton2, import_CircularProgress2, import_Autocomplete2, import_Checkbox, import_FormControlLabel, import_Alert, import_Tabs, import_Tab, import_icons_material3, generateDefaultAlias, emptyForm, ALL_PROXY_MODELS, SNIPPET_FILE_HINTS, SnippetTabs, GenerateKeyDialog;
|
|
1506
|
+
var import_react4, import_Box4, import_Typography4, import_Dialog2, import_DialogTitle2, import_DialogContent2, import_DialogActions2, import_TextField2, import_MenuItem, import_Button3, import_IconButton2, import_CircularProgress2, import_Autocomplete2, import_Checkbox, import_FormControlLabel, import_Alert, import_Accordion, import_AccordionSummary, import_AccordionDetails, import_Tabs, import_Tab, import_icons_material3, generateDefaultAlias, emptyForm, ALL_PROXY_MODELS, SNIPPET_FILE_HINTS, SnippetTabs, GenerateKeyDialog;
|
|
1471
1507
|
var init_GenerateKeyDialog = __esm({
|
|
1472
1508
|
"src/components/GenerateKeyDialog.tsx"() {
|
|
1473
1509
|
"use strict";
|
|
@@ -1487,6 +1523,9 @@ var init_GenerateKeyDialog = __esm({
|
|
|
1487
1523
|
import_Checkbox = __toESM(require("@mui/material/Checkbox"));
|
|
1488
1524
|
import_FormControlLabel = __toESM(require("@mui/material/FormControlLabel"));
|
|
1489
1525
|
import_Alert = __toESM(require("@mui/material/Alert"));
|
|
1526
|
+
import_Accordion = __toESM(require("@mui/material/Accordion"));
|
|
1527
|
+
import_AccordionSummary = __toESM(require("@mui/material/AccordionSummary"));
|
|
1528
|
+
import_AccordionDetails = __toESM(require("@mui/material/AccordionDetails"));
|
|
1490
1529
|
import_Tabs = __toESM(require("@mui/material/Tabs"));
|
|
1491
1530
|
import_Tab = __toESM(require("@mui/material/Tab"));
|
|
1492
1531
|
import_icons_material3 = require("@mui/icons-material");
|
|
@@ -1806,7 +1845,7 @@ var init_GenerateKeyDialog = __esm({
|
|
|
1806
1845
|
required: true,
|
|
1807
1846
|
fullWidth: true
|
|
1808
1847
|
}
|
|
1809
|
-
), /* @__PURE__ */ import_react4.default.createElement(
|
|
1848
|
+
), /* @__PURE__ */ import_react4.default.createElement(import_Accordion.default, { disableGutters: true, elevation: 0, sx: { border: "1px solid", borderColor: "divider", "&:before": { display: "none" } } }, /* @__PURE__ */ import_react4.default.createElement(import_AccordionSummary.default, { expandIcon: /* @__PURE__ */ import_react4.default.createElement(import_icons_material3.ExpandMore, null) }, /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "body2", fontWeight: 600 }, "Advanced")), /* @__PURE__ */ import_react4.default.createElement(import_AccordionDetails.default, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ import_react4.default.createElement(
|
|
1810
1849
|
import_TextField2.default,
|
|
1811
1850
|
{
|
|
1812
1851
|
label: "TPM Limit",
|
|
@@ -1826,7 +1865,7 @@ var init_GenerateKeyDialog = __esm({
|
|
|
1826
1865
|
helperText: "Max requests per minute this key can make across all models. Leave blank for no limit.",
|
|
1827
1866
|
fullWidth: true
|
|
1828
1867
|
}
|
|
1829
|
-
))), /* @__PURE__ */ import_react4.default.createElement(import_DialogActions2.default, null, newKeyValue ? /* @__PURE__ */ import_react4.default.createElement(import_Button3.default, { onClick: handleClose, variant: "contained", color: "success" }, "Done") : /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(import_Button3.default, { onClick: handleClose }, "Cancel"), /* @__PURE__ */ import_react4.default.createElement(
|
|
1868
|
+
))))), /* @__PURE__ */ import_react4.default.createElement(import_DialogActions2.default, null, newKeyValue ? /* @__PURE__ */ import_react4.default.createElement(import_Button3.default, { onClick: handleClose, variant: "contained", color: "success" }, "Done") : /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(import_Button3.default, { onClick: handleClose }, "Cancel"), /* @__PURE__ */ import_react4.default.createElement(
|
|
1830
1869
|
import_Button3.default,
|
|
1831
1870
|
{
|
|
1832
1871
|
onClick: handleGenerate,
|
|
@@ -2423,6 +2462,10 @@ var init_TeamUsage = __esm({
|
|
|
2423
2462
|
});
|
|
2424
2463
|
|
|
2425
2464
|
// src/components/ModelsTable.tsx
|
|
2465
|
+
function isModelAllowedByTeam2(model, teamModels) {
|
|
2466
|
+
if (!teamModels || teamModels.length === 0 || teamModels.includes(ALL_PROXY_MODELS2)) return true;
|
|
2467
|
+
return teamModels.includes(model.model_name) || !!model.access_groups?.some((group) => teamModels.includes(group));
|
|
2468
|
+
}
|
|
2426
2469
|
function fmtCostPerToken(cost) {
|
|
2427
2470
|
if (cost === void 0 || cost === null) return "\u2014";
|
|
2428
2471
|
if (cost === 0) return "$0";
|
|
@@ -2436,7 +2479,7 @@ function fmtTokens(n) {
|
|
|
2436
2479
|
if (n >= 1e3) return `${(n / 1e3).toFixed(0)}K`;
|
|
2437
2480
|
return String(n);
|
|
2438
2481
|
}
|
|
2439
|
-
var import_react7, import_Box7, import_Table4, import_TableBody4, import_TableCell4, import_TableContainer4, import_TableHead4, import_TableRow4, import_Typography7, import_MenuItem3, import_Select, import_FormControl, import_InputLabel, import_ContentCopy, import_Tooltip, import_Snackbar, import_Alert2, import_styles5, ModelsTable;
|
|
2482
|
+
var import_react7, import_Box7, import_Table4, import_TableBody4, import_TableCell4, import_TableContainer4, import_TableHead4, import_TableRow4, import_Typography7, import_MenuItem3, import_Select, import_FormControl, import_InputLabel, import_ContentCopy, import_Tooltip, import_Snackbar, import_Alert2, import_styles5, ALL_PROXY_MODELS2, ModelsTable;
|
|
2440
2483
|
var init_ModelsTable = __esm({
|
|
2441
2484
|
"src/components/ModelsTable.tsx"() {
|
|
2442
2485
|
"use strict";
|
|
@@ -2459,6 +2502,7 @@ var init_ModelsTable = __esm({
|
|
|
2459
2502
|
import_Alert2 = __toESM(require("@mui/material/Alert"));
|
|
2460
2503
|
init_ui();
|
|
2461
2504
|
import_styles5 = require("@mui/material/styles");
|
|
2505
|
+
ALL_PROXY_MODELS2 = "all-proxy-models";
|
|
2462
2506
|
ModelsTable = ({ allModels, teams, loading }) => {
|
|
2463
2507
|
const theme = (0, import_styles5.useTheme)();
|
|
2464
2508
|
const [selectedTeamId, setSelectedTeamId] = (0, import_react7.useState)("");
|
|
@@ -2469,10 +2513,7 @@ var init_ModelsTable = __esm({
|
|
|
2469
2513
|
);
|
|
2470
2514
|
const filteredModels = (0, import_react7.useMemo)(() => {
|
|
2471
2515
|
if (!selectedTeam) return [];
|
|
2472
|
-
|
|
2473
|
-
if (teamModels.length === 0) return allModels;
|
|
2474
|
-
const allowed = new Set(teamModels);
|
|
2475
|
-
return allModels.filter((m) => allowed.has(m.model_name));
|
|
2516
|
+
return allModels.filter((model) => isModelAllowedByTeam2(model, selectedTeam.models));
|
|
2476
2517
|
}, [allModels, selectedTeam]);
|
|
2477
2518
|
const handleCopyModelId = (0, import_react7.useCallback)((modelId) => {
|
|
2478
2519
|
navigator.clipboard.writeText(modelId).then(() => setCopiedSnackbar(true));
|
|
@@ -3121,6 +3162,7 @@ var init_LiteLLMPage = __esm({
|
|
|
3121
3162
|
var index_exports = {};
|
|
3122
3163
|
__export(index_exports, {
|
|
3123
3164
|
DashboardHeader: () => DashboardHeader,
|
|
3165
|
+
GenerateKeyDialog: () => GenerateKeyDialog,
|
|
3124
3166
|
KeysTable: () => KeysTable,
|
|
3125
3167
|
LiteLLMHomeWidget: () => LiteLLMHomeWidget,
|
|
3126
3168
|
LiteLLMPage: () => LiteLLMPage,
|
|
@@ -3268,5 +3310,6 @@ var LiteLLMHomeWidget = ({
|
|
|
3268
3310
|
};
|
|
3269
3311
|
|
|
3270
3312
|
// src/index.ts
|
|
3313
|
+
init_GenerateKeyDialog();
|
|
3271
3314
|
init_api();
|
|
3272
3315
|
//# sourceMappingURL=index.cjs.js.map
|