@acarmisc/backstage-plugin-litellm 0.27.0 → 0.29.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/api.d.ts +25 -3
- package/dist/budget.d.ts +24 -0
- package/dist/components/AuditLog.d.ts +2 -2
- package/dist/components/BudgetLimitList.d.ts +7 -7
- package/dist/components/DashboardHeader.d.ts +5 -3
- package/dist/components/GenerateKeyButton.d.ts +6 -2
- package/dist/components/GenerateKeyDialog.d.ts +2 -2
- package/dist/components/KeyFormDialog.d.ts +4 -16
- package/dist/components/KeySnippets.d.ts +20 -0
- package/dist/components/KeysTable.d.ts +5 -2
- package/dist/components/LiteLLMBudgetGauges.d.ts +20 -18
- package/dist/components/LiteLLMBudgetWidget.d.ts +14 -3
- package/dist/components/LiteLLMHomeWidget.d.ts +7 -2
- package/dist/components/LiteLLMPage.d.ts +2 -2
- package/dist/components/ModelsTable.d.ts +2 -2
- package/dist/components/TeamUsage.d.ts +4 -2
- package/dist/components/UsageStats.d.ts +4 -2
- package/dist/components/keyFormHelpers.d.ts +14 -0
- package/dist/components/ui/Gauge.d.ts +24 -0
- package/dist/components/ui/Meter.d.ts +13 -0
- package/dist/components/ui/charts.d.ts +34 -0
- package/dist/components/ui/index.d.ts +6 -0
- package/dist/components/ui/pills.d.ts +23 -0
- package/dist/components/ui/surfaces.d.ts +65 -0
- package/dist/components/ui/tokens.d.ts +52 -0
- package/dist/ctas.d.ts +28 -0
- package/dist/dates.d.ts +25 -0
- package/dist/feedback.d.ts +17 -0
- package/dist/format.d.ts +37 -1
- package/dist/homeWidgetHelpers.d.ts +40 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/useCopyToClipboard.d.ts +30 -0
- package/dist/hooks/useLiteLLMProfile.d.ts +32 -0
- package/dist/index.cjs.js +4935 -2814
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.esm.js +4971 -2835
- package/dist/index.esm.js.map +4 -4
- package/dist/keyFilter.d.ts +12 -0
- package/dist/keyFormValidation.d.ts +38 -0
- package/dist/keyLabels.d.ts +16 -0
- package/dist/permissions.d.ts +1 -5
- package/dist/plugin.d.ts +6 -5
- package/dist/profileCache.d.ts +46 -0
- package/dist/routeHelpers.d.ts +6 -0
- package/dist/routes.d.ts +1 -0
- package/dist/types.d.ts +15 -189
- package/dist/unprovisionedCopy.d.ts +7 -0
- package/dist/widgetState.d.ts +54 -0
- package/package.json +5 -2
- package/dist/api.test.d.ts +0 -1
- package/dist/budget.test.d.ts +0 -1
- package/dist/components/ui.d.ts +0 -206
- package/dist/format.test.d.ts +0 -1
- package/dist/permissions.test.d.ts +0 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure filtering functions for key lists.
|
|
3
|
+
*/
|
|
4
|
+
import { VirtualKey } from './types';
|
|
5
|
+
export type KeyFilterType = 'expired' | 'expiring' | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Filter keys by expiry status.
|
|
8
|
+
* @param keys List of keys to filter
|
|
9
|
+
* @param filter Filter type: 'expired', 'expiring', or undefined (no filter)
|
|
10
|
+
* @returns Filtered list of keys
|
|
11
|
+
*/
|
|
12
|
+
export declare function filterKeysByStatus(keys: VirtualKey[], filter: KeyFilterType): VirtualKey[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { GenerateKeyRequest, UpdateKeyRequest } from './types';
|
|
2
|
+
export interface ValidationErrors {
|
|
3
|
+
alias?: string;
|
|
4
|
+
team?: string;
|
|
5
|
+
budget?: string;
|
|
6
|
+
duration?: string;
|
|
7
|
+
models?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ValidationOptions {
|
|
10
|
+
teamRequired?: boolean;
|
|
11
|
+
/** True when the user has ticked the 'Unlimited budget' checkbox. */
|
|
12
|
+
unlimitedBudget?: boolean;
|
|
13
|
+
isCreate?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Validates a key form (create or edit mode).
|
|
17
|
+
* Returns a map of field names to error messages.
|
|
18
|
+
* A field with no error is absent from the map.
|
|
19
|
+
*/
|
|
20
|
+
export declare function validateKeyForm(formData: GenerateKeyRequest | UpdateKeyRequest, options?: ValidationOptions): ValidationErrors;
|
|
21
|
+
/**
|
|
22
|
+
* Returns the first field with an error, in a consistent order.
|
|
23
|
+
* Used to focus the first invalid field on submit.
|
|
24
|
+
*/
|
|
25
|
+
export declare function firstInvalidField(errors: ValidationErrors, isCreate?: boolean): string | null;
|
|
26
|
+
/**
|
|
27
|
+
* Compute the expiry date from a duration string and the current date.
|
|
28
|
+
* Supported: 'd' (days), 'w' (weeks), 'm' (months), 'y' (years).
|
|
29
|
+
* Example: expiryPreview('30d', new Date('2026-09-29')) => 'Expires Oct 29, 2026'
|
|
30
|
+
*/
|
|
31
|
+
export declare function expiryPreview(duration: string | undefined, now?: Date): string | null;
|
|
32
|
+
/**
|
|
33
|
+
* Find the priciest input cost among selected models.
|
|
34
|
+
* Returns null if no models have pricing data.
|
|
35
|
+
*/
|
|
36
|
+
export declare function priciestInputPrice(selectedModels: Array<{
|
|
37
|
+
input_cost_per_token?: number;
|
|
38
|
+
}>): number | null;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { VirtualKey } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Returns a display label for a key: alias if present, otherwise the masked key.
|
|
4
|
+
* Handles missing alias and odd/short masked strings gracefully.
|
|
5
|
+
*/
|
|
6
|
+
export declare function keyDisplayLabel(key: VirtualKey): string;
|
|
7
|
+
/**
|
|
8
|
+
* Extracts the last 4 characters from a key's masked value.
|
|
9
|
+
* Returns empty string if the key is shorter than 4 chars.
|
|
10
|
+
*/
|
|
11
|
+
export declare function keyLast4(key: VirtualKey): string;
|
|
12
|
+
/**
|
|
13
|
+
* Generates the confirmation copy for pruning expired keys.
|
|
14
|
+
* Handles singular and plural correctly.
|
|
15
|
+
*/
|
|
16
|
+
export declare function pruneCopy(n: number): string;
|
package/dist/permissions.d.ts
CHANGED
|
@@ -1,5 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export declare const litellmTeamManagePermission: import("@backstage/plugin-permission-common").BasicPermission;
|
|
3
|
-
export declare const litellmTeamMembersManagePermission: import("@backstage/plugin-permission-common").BasicPermission;
|
|
4
|
-
export declare const litellmTeamKnowledgebaseManagePermission: import("@backstage/plugin-permission-common").BasicPermission;
|
|
5
|
-
export declare const litellmTeamMcpManagePermission: import("@backstage/plugin-permission-common").BasicPermission;
|
|
1
|
+
export { litellmKeyCreatePermission, litellmKeyRevokePermission, litellmKeyManagePermission, litellmKeyResetSpendPermission, litellmKeyUnblockPermission, litellmAuditReadPermission, litellmTeamCreatePermission, litellmTeamManagePermission, litellmTeamMembersManagePermission, litellmTeamKnowledgebaseManagePermission, litellmTeamMcpManagePermission, litellmTeamDeletePermission, litellmPermissions, } from '@acarmisc/backstage-plugin-litellm-common';
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare const litellmPlugin: import("@backstage/frontend-plugin-api").OverridableFrontendPlugin<{
|
|
2
|
+
root: import("@backstage/frontend-plugin-api").RouteRef<undefined>;
|
|
3
|
+
}, {}, {
|
|
3
4
|
"api:litellm": import("@backstage/frontend-plugin-api").OverridableExtensionDefinition<{
|
|
4
5
|
kind: "api";
|
|
5
6
|
name: undefined;
|
|
@@ -22,13 +23,13 @@ export declare const litellmPlugin: import("@backstage/frontend-plugin-api").Ove
|
|
|
22
23
|
};
|
|
23
24
|
output: import("@backstage/frontend-plugin-api").ExtensionDataRef<string, "core.routing.path", {}> | import("@backstage/frontend-plugin-api").ExtensionDataRef<import("@backstage/frontend-plugin-api").RouteRef<import("@backstage/frontend-plugin-api").AnyRouteRefParams>, "core.routing.ref", {
|
|
24
25
|
optional: true;
|
|
25
|
-
}> | import("@backstage/frontend-plugin-api").ExtensionDataRef<
|
|
26
|
+
}> | import("@backstage/frontend-plugin-api").ExtensionDataRef<import("react").JSX.Element, "core.reactElement", {}> | import("@backstage/frontend-plugin-api").ExtensionDataRef<string, "core.title", {
|
|
26
27
|
optional: true;
|
|
27
28
|
}> | import("@backstage/frontend-plugin-api").ExtensionDataRef<import("@backstage/frontend-plugin-api").IconElement, "core.icon", {
|
|
28
29
|
optional: true;
|
|
29
30
|
}>;
|
|
30
31
|
inputs: {
|
|
31
|
-
pages: import("@backstage/frontend-plugin-api").ExtensionInput<import("@backstage/frontend-plugin-api").ConfigurableExtensionDataRef<
|
|
32
|
+
pages: import("@backstage/frontend-plugin-api").ExtensionInput<import("@backstage/frontend-plugin-api").ConfigurableExtensionDataRef<import("react").JSX.Element, "core.reactElement", {}> | import("@backstage/frontend-plugin-api").ConfigurableExtensionDataRef<string, "core.routing.path", {}> | import("@backstage/frontend-plugin-api").ConfigurableExtensionDataRef<import("@backstage/frontend-plugin-api").RouteRef<import("@backstage/frontend-plugin-api").AnyRouteRefParams>, "core.routing.ref", {
|
|
32
33
|
optional: true;
|
|
33
34
|
}> | import("@backstage/frontend-plugin-api").ConfigurableExtensionDataRef<string, "core.title", {
|
|
34
35
|
optional: true;
|
|
@@ -44,7 +45,7 @@ export declare const litellmPlugin: import("@backstage/frontend-plugin-api").Ove
|
|
|
44
45
|
path: string;
|
|
45
46
|
title?: string;
|
|
46
47
|
icon?: import("@backstage/frontend-plugin-api").IconElement;
|
|
47
|
-
loader?: () => Promise<
|
|
48
|
+
loader?: () => Promise<import("react").JSX.Element>;
|
|
48
49
|
routeRef?: import("@backstage/frontend-plugin-api").RouteRef;
|
|
49
50
|
noHeader?: boolean;
|
|
50
51
|
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A per-API-instance promise cache with TTL and single-flight deduplication.
|
|
3
|
+
* Used to memoize the profile hook's result and reduce redundant fetches.
|
|
4
|
+
*
|
|
5
|
+
* Each API instance gets its own cache entry; entries expire after a TTL.
|
|
6
|
+
* Concurrent callers for the same key within the TTL share a single promise
|
|
7
|
+
* and wait for its result rather than issuing parallel requests.
|
|
8
|
+
*
|
|
9
|
+
* Injectable clock for testing.
|
|
10
|
+
*/
|
|
11
|
+
import { LiteLlmApiInterface } from './api';
|
|
12
|
+
export interface Clock {
|
|
13
|
+
now(): number;
|
|
14
|
+
}
|
|
15
|
+
export declare const systemClock: Clock;
|
|
16
|
+
export interface ProfileCacheEntry {
|
|
17
|
+
result: unknown;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
}
|
|
20
|
+
export declare class ProfileCache {
|
|
21
|
+
private cache;
|
|
22
|
+
private inflight;
|
|
23
|
+
private ttlMs;
|
|
24
|
+
private clock;
|
|
25
|
+
constructor(ttlMs?: number, clock?: Clock);
|
|
26
|
+
/**
|
|
27
|
+
* Fetch or return a cached value. If a concurrent call with the same key
|
|
28
|
+
* is in-flight, wait for it rather than issuing a parallel request.
|
|
29
|
+
*
|
|
30
|
+
* @param api The API instance (cache is scoped to it).
|
|
31
|
+
* @param key A string key for the result (e.g., 'profile' or a team ID).
|
|
32
|
+
* @param fetcher A thunk that returns the value to cache.
|
|
33
|
+
* @returns The cached value (hit or miss) or the result of fetcher().
|
|
34
|
+
*/
|
|
35
|
+
memoize<T>(api: LiteLlmApiInterface, key: string, fetcher: () => Promise<T>): Promise<T>;
|
|
36
|
+
/**
|
|
37
|
+
* Invalidate all cached entries for an API instance, including inflight requests.
|
|
38
|
+
*/
|
|
39
|
+
invalidate(api: LiteLlmApiInterface): void;
|
|
40
|
+
/**
|
|
41
|
+
* Invalidate every profile entry (`profile`, `profile-userInfo`,
|
|
42
|
+
* `profile-keys`, ...) and its in-flight promise, leaving unrelated keys alone.
|
|
43
|
+
*/
|
|
44
|
+
invalidateProfile(api: LiteLlmApiInterface): void;
|
|
45
|
+
}
|
|
46
|
+
export declare const profileCacheInstance: ProfileCache;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a link to the keys tab on the LiteLLM page.
|
|
3
|
+
* @param baseUrl - The base URL of the LiteLLM module (result from useRouteRef)
|
|
4
|
+
* @returns The full URL to the keys tab, or undefined if baseUrl is not available
|
|
5
|
+
*/
|
|
6
|
+
export declare function buildKeysLink(baseUrl: string | undefined): string | undefined;
|
package/dist/routes.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const rootRouteRef: import("@backstage/frontend-plugin-api").RouteRef<undefined>;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,48 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
user_id: string;
|
|
3
|
-
user_email?: string;
|
|
4
|
-
email?: string;
|
|
5
|
-
teams?: string[];
|
|
6
|
-
models?: string[];
|
|
7
|
-
max_budget?: number;
|
|
8
|
-
spend?: number;
|
|
9
|
-
current_spend?: number;
|
|
10
|
-
soft_limit?: number;
|
|
11
|
-
hard_limit?: number;
|
|
12
|
-
/** Spend-reset period for max_budget, e.g. "30d". */
|
|
13
|
-
budget_duration?: string;
|
|
14
|
-
/** Backstage-computed: true when the user belongs to litellm.audit.group */
|
|
15
|
-
can_view_audit?: boolean;
|
|
16
|
-
}
|
|
17
|
-
export interface TeamMember {
|
|
18
|
-
user_id: string;
|
|
19
|
-
user_email?: string;
|
|
20
|
-
role: 'admin' | 'user';
|
|
21
|
-
}
|
|
22
|
-
export interface TeamObjectPermission {
|
|
23
|
-
vector_stores?: string[];
|
|
24
|
-
mcp_servers?: string[];
|
|
25
|
-
mcp_access_groups?: string[];
|
|
26
|
-
}
|
|
27
|
-
export interface TeamInfo {
|
|
28
|
-
team_id: string;
|
|
29
|
-
team_alias?: string;
|
|
30
|
-
max_budget?: number;
|
|
31
|
-
budget_duration?: string;
|
|
32
|
-
spend: number;
|
|
33
|
-
/** Share of max_budget consumed (0-100), present only on redacted records. */
|
|
34
|
-
budget_pct?: number;
|
|
35
|
-
/** ok | near (>=80%) | over (>=100%), present only on redacted records. */
|
|
36
|
-
budget_status?: 'ok' | 'near' | 'over';
|
|
37
|
-
/** True when the backend stripped max_budget/spend (budget hiding enabled). */
|
|
38
|
-
budget_hidden?: boolean;
|
|
39
|
-
members_with_roles?: TeamMember[];
|
|
40
|
-
models?: string[];
|
|
41
|
-
tpm_limit?: number;
|
|
42
|
-
rpm_limit?: number;
|
|
43
|
-
metadata?: Record<string, unknown>;
|
|
44
|
-
object_permission?: TeamObjectPermission;
|
|
45
|
-
}
|
|
1
|
+
export { type UserInfo, type TeamMember, type TeamObjectPermission, type TeamInfo, type VirtualKey, type ModelInfo, type UsageModelBreakdown, type UsageKeyBreakdown, type UsageDailyPoint, type UsageDailyModelPoint, type UsageMetrics, type GenerateKeyRequest, type UpdateKeyRequest, type GenerateKeyResponse, type AuditLogEntry, type PaginatedAuditLogs, type AuditLogsParams, type CreateTeamResponse, } from '@acarmisc/backstage-plugin-litellm-common';
|
|
46
2
|
export interface VectorStoreInfo {
|
|
47
3
|
id: string;
|
|
48
4
|
name?: string;
|
|
@@ -52,120 +8,11 @@ export interface McpServerInfo {
|
|
|
52
8
|
name?: string;
|
|
53
9
|
url?: string;
|
|
54
10
|
}
|
|
55
|
-
export interface VirtualKey {
|
|
56
|
-
key: string;
|
|
57
|
-
token?: string;
|
|
58
|
-
key_alias?: string;
|
|
59
|
-
created_at: string;
|
|
60
|
-
expires_at?: string;
|
|
61
|
-
spend: number;
|
|
62
|
-
max_budget?: number;
|
|
63
|
-
budget_duration?: string;
|
|
64
|
-
tpm_limit?: number;
|
|
65
|
-
rpm_limit?: number;
|
|
66
|
-
models?: string[];
|
|
67
|
-
user_id?: string;
|
|
68
|
-
/** Team the key is bound to, when any (used to scope the model picker). */
|
|
69
|
-
team_id?: string;
|
|
70
|
-
blocked?: boolean;
|
|
71
|
-
}
|
|
72
|
-
export interface ModelInfo {
|
|
73
|
-
model_name: string;
|
|
74
|
-
mode: string;
|
|
75
|
-
supports_function_calling?: boolean;
|
|
76
|
-
supports_vision?: boolean;
|
|
77
|
-
input_cost_per_token?: number;
|
|
78
|
-
output_cost_per_token?: number;
|
|
79
|
-
max_input_tokens?: number;
|
|
80
|
-
max_output_tokens?: number;
|
|
81
|
-
/** Access group names this model belongs to (litellm.model_info.access_groups). A team's `models` list can reference a group name instead of a literal model_name. */
|
|
82
|
-
access_groups?: string[];
|
|
83
|
-
}
|
|
84
|
-
export interface UsageModelBreakdown {
|
|
85
|
-
total_spend: number;
|
|
86
|
-
total_tokens: number;
|
|
87
|
-
prompt_tokens: number;
|
|
88
|
-
completion_tokens: number;
|
|
89
|
-
api_requests: number;
|
|
90
|
-
successful_requests: number;
|
|
91
|
-
failed_requests: number;
|
|
92
|
-
}
|
|
93
|
-
export interface UsageKeyBreakdown {
|
|
94
|
-
key_alias?: string;
|
|
95
|
-
team_id?: string | null;
|
|
96
|
-
models: string[];
|
|
97
|
-
total_spend: number;
|
|
98
|
-
total_tokens: number;
|
|
99
|
-
prompt_tokens: number;
|
|
100
|
-
completion_tokens: number;
|
|
101
|
-
api_requests: number;
|
|
102
|
-
successful_requests: number;
|
|
103
|
-
failed_requests: number;
|
|
104
|
-
}
|
|
105
|
-
export interface UsageDailyPoint {
|
|
106
|
-
date: string;
|
|
107
|
-
spend: number;
|
|
108
|
-
total_tokens: number;
|
|
109
|
-
prompt_tokens: number;
|
|
110
|
-
completion_tokens: number;
|
|
111
|
-
api_requests: number;
|
|
112
|
-
successful_requests: number;
|
|
113
|
-
failed_requests: number;
|
|
114
|
-
}
|
|
115
|
-
export interface UsageDailyModelPoint {
|
|
116
|
-
date: string;
|
|
117
|
-
model: string;
|
|
118
|
-
spend: number;
|
|
119
|
-
prompt_tokens: number;
|
|
120
|
-
completion_tokens: number;
|
|
121
|
-
total_tokens: number;
|
|
122
|
-
api_requests: number;
|
|
123
|
-
successful_requests: number;
|
|
124
|
-
failed_requests: number;
|
|
125
|
-
}
|
|
126
|
-
export interface UsageMetrics {
|
|
127
|
-
total_spend: number;
|
|
128
|
-
total_tokens: number;
|
|
129
|
-
prompt_tokens: number;
|
|
130
|
-
completion_tokens: number;
|
|
131
|
-
api_requests: number;
|
|
132
|
-
successful_requests: number;
|
|
133
|
-
failed_requests: number;
|
|
134
|
-
usage_by_model: Record<string, UsageModelBreakdown>;
|
|
135
|
-
usage_by_key: Record<string, UsageKeyBreakdown>;
|
|
136
|
-
daily_usage: UsageDailyPoint[];
|
|
137
|
-
daily_by_model: UsageDailyModelPoint[];
|
|
138
|
-
}
|
|
139
|
-
export interface GenerateKeyRequest {
|
|
140
|
-
alias?: string;
|
|
141
|
-
models?: string[];
|
|
142
|
-
team_id?: string;
|
|
143
|
-
duration?: string;
|
|
144
|
-
/** Positive number caps spend; null/undefined means unlimited. */
|
|
145
|
-
max_budget?: number | null;
|
|
146
|
-
tpm_limit?: number;
|
|
147
|
-
rpm_limit?: number;
|
|
148
|
-
key_type?: string;
|
|
149
|
-
}
|
|
150
|
-
export interface UpdateKeyRequest {
|
|
151
|
-
key_alias?: string;
|
|
152
|
-
models?: string[];
|
|
153
|
-
/** Positive number caps spend; null clears it (unlimited, gated by allowUnlimitedBudget). */
|
|
154
|
-
max_budget?: number | null;
|
|
155
|
-
tpm_limit?: number;
|
|
156
|
-
rpm_limit?: number;
|
|
157
|
-
team_id?: string;
|
|
158
|
-
duration?: string;
|
|
159
|
-
}
|
|
160
|
-
export interface GenerateKeyResponse {
|
|
161
|
-
key: string;
|
|
162
|
-
key_alias?: string;
|
|
163
|
-
expires_at?: string;
|
|
164
|
-
max_budget?: number;
|
|
165
|
-
}
|
|
166
11
|
export interface LiteLlmConfig {
|
|
167
|
-
/** Publicly reachable LiteLLM proxy base URL (for snippet generation). */
|
|
168
|
-
baseUrl: string;
|
|
12
|
+
/** Publicly reachable LiteLLM proxy base URL (for snippet generation). Null if not configured. */
|
|
13
|
+
baseUrl: string | null;
|
|
14
|
+
/** Support contact for unprovisioned users (optional, e.g. 'admin@example.com' or 'Slack #support'). */
|
|
15
|
+
supportContact?: string;
|
|
169
16
|
/** Controls for the "Generate New Key" form, set via litellm.keyGeneration in app-config.yaml. */
|
|
170
17
|
keyGeneration?: {
|
|
171
18
|
/** When false (default), the "Unlimited budget" checkbox is hidden and a budget is always required. */
|
|
@@ -173,6 +20,11 @@ export interface LiteLlmConfig {
|
|
|
173
20
|
/** When true (default), a team must be selected before a key can be generated. */
|
|
174
21
|
teamRequired: boolean;
|
|
175
22
|
};
|
|
23
|
+
/** Controls for key actions, set via litellm.keyActions in app-config.yaml. */
|
|
24
|
+
keyActions?: {
|
|
25
|
+
/** Whether key owners can reset their key's spend via the frontend (gated by litellm.key.resetSpend permission). */
|
|
26
|
+
allowOwnerResetSpend?: boolean;
|
|
27
|
+
};
|
|
176
28
|
/** Team-management surface controls, set via litellm.teamAdmin in app-config.yaml. */
|
|
177
29
|
teamManagement?: {
|
|
178
30
|
/** True only when the permission framework is enabled AND an admin group is configured. */
|
|
@@ -196,33 +48,6 @@ export interface DateRange {
|
|
|
196
48
|
start: Date;
|
|
197
49
|
end: Date;
|
|
198
50
|
}
|
|
199
|
-
export interface AuditLogEntry {
|
|
200
|
-
id: string;
|
|
201
|
-
updated_at: string;
|
|
202
|
-
changed_by?: string;
|
|
203
|
-
changed_by_api_key?: string;
|
|
204
|
-
action?: string;
|
|
205
|
-
table_name?: string;
|
|
206
|
-
object_id?: string;
|
|
207
|
-
before_value?: Record<string, unknown> | null;
|
|
208
|
-
updated_values?: Record<string, unknown> | null;
|
|
209
|
-
}
|
|
210
|
-
export interface PaginatedAuditLogs {
|
|
211
|
-
audit_logs: AuditLogEntry[];
|
|
212
|
-
total: number;
|
|
213
|
-
page: number;
|
|
214
|
-
page_size: number;
|
|
215
|
-
total_pages: number;
|
|
216
|
-
}
|
|
217
|
-
export interface AuditLogsParams {
|
|
218
|
-
page?: number;
|
|
219
|
-
page_size?: number;
|
|
220
|
-
start_date?: string;
|
|
221
|
-
end_date?: string;
|
|
222
|
-
action?: string;
|
|
223
|
-
table_name?: string;
|
|
224
|
-
changed_by?: string;
|
|
225
|
-
}
|
|
226
51
|
export interface CreateTeamRequest {
|
|
227
52
|
team_alias: string;
|
|
228
53
|
models: string[];
|
|
@@ -230,6 +55,11 @@ export interface CreateTeamRequest {
|
|
|
230
55
|
budget_duration?: string;
|
|
231
56
|
tpm_limit?: number;
|
|
232
57
|
rpm_limit?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Optimistic concurrency: the `metadata.updated_at_iso` the edit was based on.
|
|
60
|
+
* The server answers 409 when the stored value has moved on.
|
|
61
|
+
*/
|
|
62
|
+
expectedUpdatedAtIso?: string;
|
|
233
63
|
}
|
|
234
64
|
export interface UpdateTeamRequest {
|
|
235
65
|
team_alias?: string;
|
|
@@ -240,7 +70,3 @@ export interface UpdateTeamRequest {
|
|
|
240
70
|
tpm_limit?: number;
|
|
241
71
|
rpm_limit?: number;
|
|
242
72
|
}
|
|
243
|
-
export interface CreateTeamResponse {
|
|
244
|
-
team_id: string;
|
|
245
|
-
team_alias?: string;
|
|
246
|
-
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copy for unprovisioned users.
|
|
3
|
+
*/
|
|
4
|
+
export declare function getUnprovisionedTitle(): string;
|
|
5
|
+
export declare function getUnprovisionedMessage(supportContact?: string): string;
|
|
6
|
+
export declare function getAdminDetailsTitle(): string;
|
|
7
|
+
export declare function getAdminDetailsMessage(): string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget state machine for loading, error, and ready states.
|
|
3
|
+
*
|
|
4
|
+
* Discriminated union that represents the overall state of a widget:
|
|
5
|
+
* - 'loading': profile or usage data is being fetched
|
|
6
|
+
* - 'unprovisioned': user has no LiteLLM account (provisioning error)
|
|
7
|
+
* - 'error': a data fetch failed (non-provisioning error)
|
|
8
|
+
* - 'ready': data is available; usageUnavailable indicates failed usage fetch
|
|
9
|
+
*/
|
|
10
|
+
export declare const USAGE_UNAVAILABLE_MSG = "Usage unavailable";
|
|
11
|
+
export declare const UNPROVISIONED_MSG = "LiteLLM account not set up. Ask your admin.";
|
|
12
|
+
/**
|
|
13
|
+
* Detects whether an error represents a provisioning error.
|
|
14
|
+
*
|
|
15
|
+
* The backend answers 404 with body `{ error: 'User not found in LiteLLM' }`
|
|
16
|
+
* when the user hasn't been provisioned. `ApiError` uses that `error` text as
|
|
17
|
+
* its message, and `useLiteLLMProfile` surfaces failures as a plain message
|
|
18
|
+
* string, so all three shapes are recognised: an ApiError (status + body), an
|
|
19
|
+
* Error, or the bare message string.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isUnprovisionedError(error: unknown): boolean;
|
|
22
|
+
export type WidgetViewState = {
|
|
23
|
+
kind: 'loading';
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'unprovisioned';
|
|
26
|
+
} | {
|
|
27
|
+
kind: 'error';
|
|
28
|
+
message: string;
|
|
29
|
+
} | {
|
|
30
|
+
kind: 'ready';
|
|
31
|
+
usageUnavailable: boolean;
|
|
32
|
+
};
|
|
33
|
+
export interface WidgetStateParams {
|
|
34
|
+
/** True if profile data is currently loading */
|
|
35
|
+
loading: boolean;
|
|
36
|
+
/** Error from profile fetch (getUserInfo). null if no error. */
|
|
37
|
+
error: unknown;
|
|
38
|
+
/** User info object; null if not loaded or unprovisioned */
|
|
39
|
+
userInfo: unknown;
|
|
40
|
+
/** Error from usage fetch. null if no error. */
|
|
41
|
+
usageError: unknown;
|
|
42
|
+
/** Number of keys; optional. Used to determine if the user has any keys. */
|
|
43
|
+
hasKeys?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Determines the overall widget view state based on loading and error conditions.
|
|
47
|
+
*
|
|
48
|
+
* Priority:
|
|
49
|
+
* 1. If loading, return 'loading'
|
|
50
|
+
* 2. If profile error is unprovisioned, return 'unprovisioned'
|
|
51
|
+
* 3. If profile error (any other), return 'error'
|
|
52
|
+
* 4. Otherwise, return 'ready' with usageUnavailable flag based on usageError
|
|
53
|
+
*/
|
|
54
|
+
export declare function widgetViewState({ loading, error, userInfo: _userInfo, usageError, hasKeys: _hasKeys, }: WidgetStateParams): WidgetViewState;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acarmisc/backstage-plugin-litellm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "frontend-plugin",
|
|
6
6
|
"pluginId": "litellm",
|
|
@@ -34,12 +34,13 @@
|
|
|
34
34
|
"scripts": {
|
|
35
35
|
"build": "node build.js && tsc -p tsconfig.json",
|
|
36
36
|
"lint": "eslint src dev --ext .ts,.tsx",
|
|
37
|
-
"test": "tsc -p tsconfig.test.json && node --test
|
|
37
|
+
"test": "tsc -p tsconfig.test.json && node --import ./test-support/register.mjs --test --test-timeout=30000 \"dist-test/**/*.test.js\"",
|
|
38
38
|
"api-report": "npm run build && api-extractor run --local --verbose",
|
|
39
39
|
"prepack": "npm run build",
|
|
40
40
|
"postpack": ""
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
+
"@acarmisc/backstage-plugin-litellm-common": "0.1.0",
|
|
43
44
|
"@backstage/catalog-model": "^1.9.0",
|
|
44
45
|
"@backstage/core-components": "^0.18.10",
|
|
45
46
|
"@backstage/core-plugin-api": "^1.12.6",
|
|
@@ -69,9 +70,11 @@
|
|
|
69
70
|
"@testing-library/jest-dom": "^6.0.0",
|
|
70
71
|
"@testing-library/react": "^16.0.0",
|
|
71
72
|
"@testing-library/user-event": "^14.0.0",
|
|
73
|
+
"@types/jsdom": "^30.0.0",
|
|
72
74
|
"@types/node": "^20.19.43",
|
|
73
75
|
"@types/react": "^18.2.0",
|
|
74
76
|
"esbuild": "^0.28.0",
|
|
77
|
+
"jsdom": "^26.1.0",
|
|
75
78
|
"react-dom": "^18.2.0",
|
|
76
79
|
"react-router-dom": "^6.30.0",
|
|
77
80
|
"typescript": "^5.9.3"
|
package/dist/api.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/budget.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|