@acarmisc/backstage-plugin-litellm 0.33.0 → 0.34.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/README.md +55 -66
- package/dist/components/KeyFormDialog.d.ts +0 -2
- package/dist/components/LiteLLMBudgetGauges.d.ts +0 -1
- package/dist/components/keyFormHelpers.d.ts +0 -1
- package/dist/hooks/useCopyToClipboard.d.ts +0 -5
- package/dist/index.cjs.js +11 -44
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.d.ts +2 -3
- package/dist/index.esm.js +22 -56
- package/dist/index.esm.js.map +4 -4
- package/package.json +4 -10
- package/dist/components/GenerateKeyDialog.d.ts +0 -21
- package/dist/permissions.d.ts +0 -1
package/README.md
CHANGED
|
@@ -1,97 +1,86 @@
|
|
|
1
1
|
# @acarmisc/backstage-plugin-litellm
|
|
2
2
|
|
|
3
|
-
Frontend for the **Backstage LiteLLM Governance Plugin** — lets developers manage
|
|
3
|
+
Frontend for the **Backstage LiteLLM Governance Plugin** — lets developers manage
|
|
4
|
+
their LiteLLM virtual keys and follow their AI usage and budgets from Backstage.
|
|
4
5
|
|
|
5
|
-
Built
|
|
6
|
+
Built for the [New Frontend System](https://backstage.io/docs/frontend-system/)
|
|
7
|
+
(`@backstage/frontend-plugin-api`). It needs the backend,
|
|
8
|
+
[`@acarmisc/backstage-plugin-litellm-backend`](https://www.npmjs.com/package/@acarmisc/backstage-plugin-litellm-backend),
|
|
9
|
+
which talks to LiteLLM and enforces every rule.
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Screenshots
|
|
12
|
-
|
|
13
|
-
| View | Preview |
|
|
14
|
-
|------|---------|
|
|
15
|
-
| Home widget — `LiteLLMHomeWidget` |  |
|
|
16
|
-
| Overview / Usage Analytics |  |
|
|
17
|
-
| Keys tab — virtual key inventory |  |
|
|
18
|
-
| Generate New Key dialog |  |
|
|
19
|
-
| Models tab |  |
|
|
20
|
-
| Compact "Create Key" card |  |
|
|
11
|
+
Full documentation — adoption guide, configuration, permissions, security model
|
|
12
|
+
and architecture — starts at the
|
|
13
|
+
[project README](https://github.com/acarmisc/backstage-plugin-litellm-govai#readme).
|
|
21
14
|
|
|
22
15
|
## Installation
|
|
23
16
|
|
|
24
|
-
This plugin is designed to be used **within a Backstage monorepo**.
|
|
25
|
-
|
|
26
17
|
```bash
|
|
27
|
-
yarn
|
|
18
|
+
yarn --cwd packages/app add @acarmisc/backstage-plugin-litellm
|
|
28
19
|
```
|
|
29
20
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
## Usage
|
|
33
|
-
|
|
34
|
-
### Full page
|
|
35
|
-
|
|
36
|
-
The `LiteLLMPage` component renders the four-tab governance view: **Overview** (usage KPIs + charts), **Keys** (virtual key inventory), **Teams** (team-scoped usage), and **Models** (proxy model catalog).
|
|
21
|
+
If your app discovers features from its dependencies (`app.packages: all`),
|
|
22
|
+
the plugin is picked up automatically. Otherwise register it:
|
|
37
23
|
|
|
38
24
|
```tsx
|
|
39
|
-
import { litellmPlugin, LiteLLMPage } from '@acarmisc/backstage-plugin-litellm';
|
|
40
|
-
|
|
41
25
|
// packages/app/src/App.tsx
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-

|
|
26
|
+
import { createApp } from '@backstage/frontend-defaults';
|
|
27
|
+
import litellmPlugin from '@acarmisc/backstage-plugin-litellm';
|
|
46
28
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
```tsx
|
|
52
|
-
import { LiteLLMHomeWidget } from '@acarmisc/backstage-plugin-litellm';
|
|
53
|
-
|
|
54
|
-
<LiteLLMHomeWidget defaultPeriod="7d" />
|
|
29
|
+
const app = createApp({
|
|
30
|
+
features: [litellmPlugin],
|
|
31
|
+
});
|
|
55
32
|
```
|
|
56
33
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
| `defaultPeriod` | `'today' \| '7d' \| '30d'` | `'7d'` | Period shown on first render |
|
|
60
|
-
| `title` | `string` | `'LiteLLM Usage'` | Card title override |
|
|
34
|
+
This adds the `/litellm` page and the `liteLlmApiRef` API used by every
|
|
35
|
+
component below.
|
|
61
36
|
|
|
62
|
-
|
|
37
|
+
## The `/litellm` page
|
|
63
38
|
|
|
64
|
-
|
|
39
|
+
Tabs: **Overview** (usage KPIs and charts), **Keys** (your virtual keys: edit,
|
|
40
|
+
block / unblock, reset spend, delete), **Teams** (team usage, and team
|
|
41
|
+
management for admins), **Models** (the proxy's model catalogue) and **Audit
|
|
42
|
+
Log** (members of `litellm.audit.group` only). `?tab=<name>` opens a tab and
|
|
43
|
+
`?generate=1` opens the Generate New Key dialog.
|
|
65
44
|
|
|
66
|
-
|
|
45
|
+

|
|
67
46
|
|
|
68
|
-
|
|
47
|
+
## Homepage components
|
|
69
48
|
|
|
70
|
-
|
|
49
|
+
| Component | What it shows |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `LiteLLMHomeWidget` | Spend and tokens for `Today` / `7d` / `30d` with a daily sparkline |
|
|
52
|
+
| `LiteLLMBudgetWidget` | The budget hierarchy (key → personal → team → global) with a meter per limit |
|
|
53
|
+
| `LiteLLMBudgetGauges` | A condensed budget card: one ring per level and a month-to-date chart |
|
|
54
|
+
| `GenerateKeyButton` | The shared "Generate New Key" button (`onClick`, or `to="/litellm?generate=1"`) |
|
|
71
55
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
56
|
+
```tsx
|
|
57
|
+
import {
|
|
58
|
+
LiteLLMHomeWidget,
|
|
59
|
+
LiteLLMBudgetGauges,
|
|
60
|
+
} from '@acarmisc/backstage-plugin-litellm';
|
|
77
61
|
|
|
78
|
-
|
|
62
|
+
<LiteLLMHomeWidget defaultPeriod="7d" />
|
|
63
|
+
<LiteLLMBudgetGauges />
|
|
64
|
+
```
|
|
79
65
|
|
|
80
|
-
|
|
66
|
+
Props for each component are documented in
|
|
67
|
+
[docs/frontend.md](https://github.com/acarmisc/backstage-plugin-litellm-govai/blob/main/docs/frontend.md).
|
|
81
68
|
|
|
82
|
-

|
|
83
70
|
|
|
84
|
-
|
|
71
|
+
To try it without a backend, run `npm start` in this package: it serves the
|
|
72
|
+
plugin with mock data at `http://localhost:3000/litellm` (see
|
|
73
|
+
[CONTRIBUTING.md](https://github.com/acarmisc/backstage-plugin-litellm-govai/blob/main/CONTRIBUTING.md#run-the-frontend-with-mock-data)).
|
|
85
74
|
|
|
86
|
-
|
|
87
|
-
- `LiteLLMPage` — main plugin page (keys, usage, team context)
|
|
88
|
-
- `LiteLLMHomeWidget` — homepage usage summary card
|
|
89
|
-
- `KeyFormDialog` — shared key form for both generating and editing a key (surfaces failures inline, warns on duplicate aliases, team-scoped model picker, unlimited-budget toggle when gated on)
|
|
90
|
-
- `GenerateKeyDialog` — deprecated wrapper around `KeyFormDialog` with `mode="create"`
|
|
91
|
-
- `DashboardHeader`, `KeysTable`, `UsageStats`, `TeamUsage` — individual page sections, exported for composition
|
|
92
|
-
- `LiteLlmApi`, `liteLlmApiRef` — API client and its Backstage API ref
|
|
75
|
+
## Other exports
|
|
93
76
|
|
|
94
|
-
|
|
77
|
+
- `litellmPlugin` (also the default export)
|
|
78
|
+
- `LiteLLMPage`, and the building blocks it uses: `DashboardHeader`,
|
|
79
|
+
`KeysTable`, `UsageStats`, `TeamUsage`, `KeyFormDialog`, `ManageTeamDialog`.
|
|
80
|
+
Prefer `LiteLLMPage`; composing the pieces yourself means wiring their data
|
|
81
|
+
and callbacks the way the page does.
|
|
82
|
+
- `LiteLlmApi`, `liteLlmApiRef`, the shared API types, and the
|
|
83
|
+
`litellmTeam*Permission` definitions.
|
|
95
84
|
|
|
96
85
|
## License
|
|
97
86
|
|
|
@@ -26,5 +26,3 @@ export interface KeyFormDialogProps {
|
|
|
26
26
|
onGetConfig: () => Promise<LiteLlmConfig>;
|
|
27
27
|
}
|
|
28
28
|
export declare const KeyFormDialog: FC<KeyFormDialogProps>;
|
|
29
|
-
export declare function fmtCost(perToken?: number): string | null;
|
|
30
|
-
export declare function formatContextWindow(maxInput?: number, maxOutput?: number): string | null;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { VirtualKey, ModelInfo, GenerateKeyRequest, UpdateKeyRequest } from '../types';
|
|
2
|
-
export declare const generateDefaultAlias: (username?: string) => string;
|
|
3
2
|
export declare const createForm: (username?: string) => GenerateKeyRequest;
|
|
4
3
|
export declare const editForm: (k: VirtualKey) => UpdateKeyRequest;
|
|
5
4
|
export declare function isModelAllowedByTeam(model: ModelInfo, teamModels?: string[]): boolean;
|
|
@@ -2,11 +2,6 @@
|
|
|
2
2
|
* Pure helper: determine if the Clipboard API is available.
|
|
3
3
|
*/
|
|
4
4
|
export declare function isClipboardApiAvailable(): boolean;
|
|
5
|
-
/**
|
|
6
|
-
* Pure helper: fallback copy via textarea and document.execCommand.
|
|
7
|
-
* Returns true if successful, false otherwise.
|
|
8
|
-
*/
|
|
9
|
-
export declare function fallbackCopyToClipboard(text: string): boolean;
|
|
10
5
|
/**
|
|
11
6
|
* Pure helper: create a timer for the copied state.
|
|
12
7
|
* Returns the timer ID so the caller can manage cleanup.
|
package/dist/index.cjs.js
CHANGED
|
@@ -1843,8 +1843,6 @@ var init_KeysTable = __esm({
|
|
|
1843
1843
|
setPruneSubmitting(true);
|
|
1844
1844
|
try {
|
|
1845
1845
|
await onPruneExpiredKeys();
|
|
1846
|
-
} catch (error) {
|
|
1847
|
-
console.error("Failed to prune expired keys:", error);
|
|
1848
1846
|
} finally {
|
|
1849
1847
|
setPruneSubmitting(false);
|
|
1850
1848
|
setPruneConfirmCount(null);
|
|
@@ -1913,7 +1911,8 @@ var init_KeysTable = __esm({
|
|
|
1913
1911
|
bgcolor: (0, import_styles7.alpha)(theme.palette.text.primary, theme.palette.mode === "dark" ? 0.08 : 0.05),
|
|
1914
1912
|
px: 0.75,
|
|
1915
1913
|
py: 0.375,
|
|
1916
|
-
borderRadius: "5px"
|
|
1914
|
+
borderRadius: "5px",
|
|
1915
|
+
whiteSpace: "nowrap"
|
|
1917
1916
|
}),
|
|
1918
1917
|
children: shortKeyId(keyId)
|
|
1919
1918
|
}
|
|
@@ -5897,15 +5896,6 @@ var init_dates = __esm({
|
|
|
5897
5896
|
}
|
|
5898
5897
|
});
|
|
5899
5898
|
|
|
5900
|
-
// src/permissions.ts
|
|
5901
|
-
var import_backstage_plugin_litellm_common5;
|
|
5902
|
-
var init_permissions = __esm({
|
|
5903
|
-
"src/permissions.ts"() {
|
|
5904
|
-
"use strict";
|
|
5905
|
-
import_backstage_plugin_litellm_common5 = require("@acarmisc/backstage-plugin-litellm-common");
|
|
5906
|
-
}
|
|
5907
|
-
});
|
|
5908
|
-
|
|
5909
5899
|
// src/feedback.ts
|
|
5910
5900
|
function toastFor(kind, errorMsg) {
|
|
5911
5901
|
switch (kind) {
|
|
@@ -6014,7 +6004,7 @@ function initDateRange() {
|
|
|
6014
6004
|
else start.setDate(start.getDate() - 7);
|
|
6015
6005
|
return { start, end };
|
|
6016
6006
|
}
|
|
6017
|
-
var import_react13, import_Box17, import_Alert6, import_Button7, import_Typography15, import_Tabs2, import_Tab2, import_Grid2, import_Accordion2, import_AccordionSummary2, import_AccordionDetails2, import_ExpandMore, import_react_router_dom, import_react_use2, import_core_plugin_api5, import_core_components3, import_plugin_permission_react3, import_jsx_runtime18, PERIOD_LS_KEY2, PAGE_TABS, isPageTab, LiteLLMPage;
|
|
6007
|
+
var import_react13, import_Box17, import_Alert6, import_Button7, import_Typography15, import_Tabs2, import_Tab2, import_Grid2, import_Accordion2, import_AccordionSummary2, import_AccordionDetails2, import_ExpandMore, import_react_router_dom, import_react_use2, import_core_plugin_api5, import_core_components3, import_plugin_permission_react3, import_backstage_plugin_litellm_common5, import_jsx_runtime18, PERIOD_LS_KEY2, PAGE_TABS, isPageTab, LiteLLMPage;
|
|
6018
6008
|
var init_LiteLLMPage = __esm({
|
|
6019
6009
|
"src/components/LiteLLMPage.tsx"() {
|
|
6020
6010
|
"use strict";
|
|
@@ -6046,7 +6036,7 @@ var init_LiteLLMPage = __esm({
|
|
|
6046
6036
|
init_AuditLog();
|
|
6047
6037
|
init_api();
|
|
6048
6038
|
init_dates();
|
|
6049
|
-
|
|
6039
|
+
import_backstage_plugin_litellm_common5 = require("@acarmisc/backstage-plugin-litellm-common");
|
|
6050
6040
|
init_feedback();
|
|
6051
6041
|
init_teamMemberManager();
|
|
6052
6042
|
init_unprovisionedCopy();
|
|
@@ -6672,7 +6662,6 @@ var index_exports = {};
|
|
|
6672
6662
|
__export(index_exports, {
|
|
6673
6663
|
DashboardHeader: () => DashboardHeader,
|
|
6674
6664
|
GenerateKeyButton: () => GenerateKeyButton,
|
|
6675
|
-
GenerateKeyDialog: () => GenerateKeyDialog,
|
|
6676
6665
|
KeyFormDialog: () => KeyFormDialog,
|
|
6677
6666
|
KeysTable: () => KeysTable,
|
|
6678
6667
|
LiteLLMBudgetGauges: () => LiteLLMBudgetGauges,
|
|
@@ -6683,13 +6672,14 @@ __export(index_exports, {
|
|
|
6683
6672
|
ManageTeamDialog: () => ManageTeamDialog,
|
|
6684
6673
|
TeamUsage: () => TeamUsage,
|
|
6685
6674
|
UsageStats: () => UsageStats,
|
|
6675
|
+
default: () => litellmPlugin,
|
|
6686
6676
|
liteLlmApiRef: () => liteLlmApiRef,
|
|
6687
6677
|
litellmPlugin: () => litellmPlugin,
|
|
6688
|
-
litellmTeamCreatePermission: () =>
|
|
6689
|
-
litellmTeamKnowledgebaseManagePermission: () =>
|
|
6690
|
-
litellmTeamManagePermission: () =>
|
|
6691
|
-
litellmTeamMcpManagePermission: () =>
|
|
6692
|
-
litellmTeamMembersManagePermission: () =>
|
|
6678
|
+
litellmTeamCreatePermission: () => import_backstage_plugin_litellm_common6.litellmTeamCreatePermission,
|
|
6679
|
+
litellmTeamKnowledgebaseManagePermission: () => import_backstage_plugin_litellm_common6.litellmTeamKnowledgebaseManagePermission,
|
|
6680
|
+
litellmTeamManagePermission: () => import_backstage_plugin_litellm_common6.litellmTeamManagePermission,
|
|
6681
|
+
litellmTeamMcpManagePermission: () => import_backstage_plugin_litellm_common6.litellmTeamMcpManagePermission,
|
|
6682
|
+
litellmTeamMembersManagePermission: () => import_backstage_plugin_litellm_common6.litellmTeamMembersManagePermission
|
|
6693
6683
|
});
|
|
6694
6684
|
module.exports = __toCommonJS(index_exports);
|
|
6695
6685
|
|
|
@@ -7620,30 +7610,7 @@ var LiteLLMBudgetGauges = ({
|
|
|
7620
7610
|
// src/index.ts
|
|
7621
7611
|
init_KeyFormDialog();
|
|
7622
7612
|
init_GenerateKeyButton();
|
|
7623
|
-
|
|
7624
|
-
// src/components/GenerateKeyDialog.tsx
|
|
7625
|
-
init_KeyFormDialog();
|
|
7626
|
-
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
7627
|
-
var GenerateKeyDialog = (props) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
7628
|
-
KeyFormDialog,
|
|
7629
|
-
{
|
|
7630
|
-
open: props.open,
|
|
7631
|
-
onClose: props.onClose,
|
|
7632
|
-
mode: "create",
|
|
7633
|
-
keys: props.keys,
|
|
7634
|
-
models: props.models,
|
|
7635
|
-
teams: props.teams,
|
|
7636
|
-
username: props.username,
|
|
7637
|
-
keyGenerationSettings: props.keyGenerationSettings,
|
|
7638
|
-
onCreateKey: props.onGenerateKey,
|
|
7639
|
-
onUpdateKey: async () => {
|
|
7640
|
-
},
|
|
7641
|
-
onGetConfig: props.onGetConfig
|
|
7642
|
-
}
|
|
7643
|
-
);
|
|
7644
|
-
|
|
7645
|
-
// src/index.ts
|
|
7646
7613
|
init_ManageTeamDialog();
|
|
7647
7614
|
init_api();
|
|
7648
|
-
|
|
7615
|
+
var import_backstage_plugin_litellm_common6 = require("@acarmisc/backstage-plugin-litellm-common");
|
|
7649
7616
|
//# sourceMappingURL=index.cjs.js.map
|