@acarmisc/backstage-plugin-litellm 0.23.0 → 0.25.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/budget.d.ts CHANGED
@@ -45,6 +45,36 @@ export interface BudgetSummary {
45
45
  * team falls back to the owner's personal budget.
46
46
  */
47
47
  export declare function buildBudgetSummary(user: UserInfo | null, teams: TeamInfo[], keys: VirtualKey[], maxKeys?: number): BudgetSummary;
48
+ /**
49
+ * Every concrete limit across all levels, keys first then personal then
50
+ * teams. The per-level slices are already sorted by proximity to the cap, so
51
+ * each level's limits stay ordered; this is the flat list for a "show all
52
+ * limits" view. Keys beyond a display `maxKeys` are not included — build the
53
+ * summary with a large `maxKeys` when the full list is needed.
54
+ */
55
+ export declare function allBudgetLimits(summary: BudgetSummary): BudgetLimit[];
56
+ /** One gauge in the condensed homepage card — a single enforcement level. */
57
+ export interface BudgetGauge {
58
+ kind: 'key' | 'user' | 'team';
59
+ /**
60
+ * The limit of this level nearest its cap, or undefined when the user has
61
+ * no cap at this level (render an empty gauge).
62
+ */
63
+ limit?: BudgetLimit;
64
+ /** How many limits apply at this level (1 for a personal budget). */
65
+ count: number;
66
+ }
67
+ /**
68
+ * Collapses a `BudgetSummary` to exactly one gauge per enforcement level —
69
+ * key, user, team — carrying the limit nearest its cap and how many limits
70
+ * that level holds. Every level is always returned, with `limit` undefined
71
+ * when the user has no cap there, so the caller can render a stable row.
72
+ *
73
+ * Pass a summary built with a large `maxKeys` (e.g. `keys.length`) so the
74
+ * nearest key is present even when it falls outside the display cap; a key
75
+ * count hidden by that cap is still reflected in `count`.
76
+ */
77
+ export declare function buildBudgetGauges(summary: BudgetSummary): BudgetGauge[];
48
78
  /**
49
79
  * One-line summary of a `BudgetSummary`, for a collapsed/compact header:
50
80
  * how many concrete limits the user is subject to, and the one closest to
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Shared budget-limit presentation used by both budget cards: the
3
+ * `LiteLLMBudgetWidget` (full/compact meter list) and the condensed
4
+ * `LiteLLMBudgetGauges` (expanded "all limits" view). Keeping the card in one
5
+ * place means a limit reads identically wherever it is shown.
6
+ */
7
+ import React from 'react';
8
+ import type { Theme } from '@mui/material/styles';
9
+ import { BudgetLimit } from '../budget';
10
+ import { Tone } from './ui';
11
+ /** Semantic colour for a tone, from the host theme. */
12
+ export declare function levelToneColor(tone: Tone | undefined, theme: Theme): string;
13
+ /** Spend-vs-cap meter card for a single limit. */
14
+ export declare const LimitCard: React.FC<{
15
+ limit: BudgetLimit;
16
+ }>;
17
+ /** A LimitCard prefixed with a small KEY / USER / TEAM tag. */
18
+ export declare const TaggedLimit: React.FC<{
19
+ limit: BudgetLimit;
20
+ }>;
21
+ /** A key-budget note under a limit list — plain text when no href is given. */
22
+ export declare const MoreKeysNote: React.FC<{
23
+ count: number;
24
+ href?: string;
25
+ label?: string;
26
+ }>;
27
+ /**
28
+ * Flat list of concrete limits across every level, as tagged meter cards.
29
+ * Used by the condensed gauges card's expanded view; the full widget renders
30
+ * its own grouped-by-level rail instead.
31
+ */
32
+ export declare const BudgetLimitList: React.FC<{
33
+ limits: BudgetLimit[];
34
+ /** Keys beyond the supplied limits — rendered as a trailing note. */
35
+ hiddenKeyCount?: number;
36
+ keysHref?: string;
37
+ }>;
38
+ /** Inset panel used to hold a nested list of limits inside a card. */
39
+ export declare const LimitListPanel: React.FC<{
40
+ children: React.ReactNode;
41
+ }>;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Condensed budget card for a homepage column: one ring gauge per
3
+ * enforcement level (key → personal → team), each showing the limit nearest
4
+ * its cap. Where the full `LiteLLMBudgetWidget` lists every limit as a
5
+ * spend-vs-cap meter, this trades detail for density — a single row of rings
6
+ * with a label and spend figure under each.
7
+ *
8
+ * Gauges are always rendered in the same order, with an empty ring when the
9
+ * user has no cap at that level, so the card keeps a stable shape as data
10
+ * loads and across users. When a level holds several limits, the ring shows
11
+ * the one closest to its cap and a "+N more" link counts the rest.
12
+ *
13
+ * The bottom action bar is composable: pass any subset of `ctas` — mint a new
14
+ * key, open the LiteLLM module, or expand the full per-limit list in place —
15
+ * in the order you want. `action` remains an escape hatch for a fully custom
16
+ * node; when either is present it renders below a divider.
17
+ */
18
+ import React from 'react';
19
+ /** Preset action-bar buttons. `label` overrides the default copy. */
20
+ export type BudgetCtaKind = 'new-key' | 'module' | 'all-limits';
21
+ export interface BudgetCtaSpec {
22
+ kind: BudgetCtaKind;
23
+ /** Override the default label. */
24
+ label?: string;
25
+ }
26
+ /** Either a bare kind (`'module'`) or a spec object (`{ kind: 'module' }`). */
27
+ export type BudgetCta = BudgetCtaKind | BudgetCtaSpec;
28
+ export interface LiteLLMBudgetGaugesProps {
29
+ /** Optional title override. Defaults to 'Budget'. */
30
+ title?: string;
31
+ /** Ring diameter in px. Defaults to 72. */
32
+ size?: number;
33
+ /** Where the "+N more" key link points. Defaults to the Keys tab. */
34
+ keysHref?: string;
35
+ /** Where the module CTA points. Defaults to the LiteLLM page. */
36
+ moduleHref?: string;
37
+ /**
38
+ * Called when the "new key" CTA is used. When omitted, the CTA deep-links
39
+ * to the module with `?generate=1`, which opens the generate-key dialog.
40
+ */
41
+ onCreateKey?: () => void;
42
+ /**
43
+ * Action-bar buttons to render, in order. Defaults to
44
+ * `['new-key', 'module', 'all-limits']`. Pass `[]` to hide the bar; the
45
+ * `all-limits` entry is dropped automatically when the user has no limits.
46
+ */
47
+ ctas?: BudgetCta[];
48
+ /** Max key limits listed in the expanded view. Defaults to 8. */
49
+ maxExpandedKeys?: number;
50
+ /** Controlled expanded state for the all-limits view. */
51
+ expanded?: boolean;
52
+ /** Initial expanded state when uncontrolled. Defaults to false. */
53
+ defaultExpanded?: boolean;
54
+ /** Notified whenever the expanded state changes. */
55
+ onExpandedChange?: (expanded: boolean) => void;
56
+ /** Fully custom node pinned below the CTAs, below a divider. */
57
+ action?: React.ReactNode;
58
+ }
59
+ export declare const LiteLLMBudgetGauges: React.FC<LiteLLMBudgetGaugesProps>;
@@ -156,6 +156,26 @@ export declare const Meter: React.FC<{
156
156
  tone?: Tone;
157
157
  height?: number;
158
158
  }>;
159
+ /**
160
+ * Ring gauge for at-a-glance ratios. Hand-drawn SVG rather than MUI's
161
+ * `CircularProgress`: the track has to stay a neutral hairline (MUI tints it
162
+ * from the bar colour, so an empty ring reads as full), and the value may
163
+ * legitimately exceed 100% — the arc clamps at a full turn while the centre
164
+ * label keeps the real number.
165
+ */
166
+ export declare const Gauge: React.FC<{
167
+ /** Share consumed, 0..100+ (unclamped for the label). */
168
+ value: number;
169
+ tone?: Tone;
170
+ /** Outer diameter in px. */
171
+ size?: number;
172
+ /** Ring thickness in px. */
173
+ thickness?: number;
174
+ /** Centre content; defaults to the rounded percentage. */
175
+ label?: React.ReactNode;
176
+ /** Small caption under the value, inside the ring. */
177
+ caption?: React.ReactNode;
178
+ }>;
159
179
  /**
160
180
  * Secondary navigation inside a card. Hand-rolled rather than a second set of
161
181
  * `Tabs` so it reads as subordinate to the page tabs instead of competing