@acarmisc/backstage-plugin-litellm-backend 0.10.0 → 0.11.1
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/config.d.ts +1 -2
- package/dist/client.js +1 -0
- package/dist/index.cjs.js +30 -14
- package/dist/index.cjs.js.map +2 -2
- package/dist/router.js +44 -6
- package/dist/teamAdmin.d.ts +10 -3
- package/dist/teamAdmin.js +12 -6
- package/dist/types.cjs.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
package/config.d.ts
CHANGED
|
@@ -184,8 +184,7 @@ export interface Config {
|
|
|
184
184
|
|
|
185
185
|
/**
|
|
186
186
|
* Hard USD ceiling for max_budget an admin may set on a team.
|
|
187
|
-
*
|
|
188
|
-
* allowUnlimitedBudget is true.
|
|
187
|
+
* @default 1000
|
|
189
188
|
* @visibility backend
|
|
190
189
|
*/
|
|
191
190
|
maxBudgetCeiling?: number;
|
package/dist/client.js
CHANGED
|
@@ -314,6 +314,7 @@ class LiteLLMClient {
|
|
|
314
314
|
team_id: raw?.team_id ?? inner.team_id ?? fallbackId ?? '',
|
|
315
315
|
team_alias: inner.team_alias ?? raw?.team_alias,
|
|
316
316
|
max_budget: inner.max_budget ?? raw?.max_budget,
|
|
317
|
+
budget_duration: inner.budget_duration ?? raw?.budget_duration,
|
|
317
318
|
spend: inner.spend ?? raw?.spend ?? 0,
|
|
318
319
|
members_with_roles: inner.members_with_roles ?? raw?.members_with_roles,
|
|
319
320
|
models: inner.models ?? raw?.models,
|
package/dist/index.cjs.js
CHANGED
|
@@ -8301,6 +8301,7 @@ var LiteLLMClient = class {
|
|
|
8301
8301
|
team_id: raw?.team_id ?? inner.team_id ?? fallbackId ?? "",
|
|
8302
8302
|
team_alias: inner.team_alias ?? raw?.team_alias,
|
|
8303
8303
|
max_budget: inner.max_budget ?? raw?.max_budget,
|
|
8304
|
+
budget_duration: inner.budget_duration ?? raw?.budget_duration,
|
|
8304
8305
|
spend: inner.spend ?? raw?.spend ?? 0,
|
|
8305
8306
|
members_with_roles: inner.members_with_roles ?? raw?.members_with_roles,
|
|
8306
8307
|
models: inner.models ?? raw?.models,
|
|
@@ -10630,6 +10631,7 @@ var litellmPermissions = [
|
|
|
10630
10631
|
|
|
10631
10632
|
// src/teamAdmin.ts
|
|
10632
10633
|
var import_plugin_permission_common2 = __toESM(require_index_cjs2());
|
|
10634
|
+
var DEFAULT_TEAM_BUDGET_CEILING = 1e3;
|
|
10633
10635
|
function isTeamManagementEnabled(config) {
|
|
10634
10636
|
const permEnabled = config.getOptionalBoolean("permission.enabled") ?? false;
|
|
10635
10637
|
const adminConfig = readTeamAdminConfig(config);
|
|
@@ -10689,9 +10691,7 @@ function readTeamAdminConfig(config) {
|
|
|
10689
10691
|
allowedModelAccessGroups: config.getOptionalStringArray(
|
|
10690
10692
|
"litellm.teamAdmin.allowedModelAccessGroups"
|
|
10691
10693
|
) ?? [],
|
|
10692
|
-
maxBudgetCeiling: config.getOptionalNumber(
|
|
10693
|
-
"litellm.teamAdmin.maxBudgetCeiling"
|
|
10694
|
-
),
|
|
10694
|
+
maxBudgetCeiling: config.getOptionalNumber("litellm.teamAdmin.maxBudgetCeiling") ?? DEFAULT_TEAM_BUDGET_CEILING,
|
|
10695
10695
|
allowUnlimitedBudget: config.getOptionalBoolean("litellm.teamAdmin.allowUnlimitedBudget") ?? false,
|
|
10696
10696
|
allowedVectorStores: config.getOptionalStringArray("litellm.teamAdmin.allowedVectorStores") ?? [],
|
|
10697
10697
|
allowedMcpServers: config.getOptionalStringArray("litellm.teamAdmin.allowedMcpServers") ?? [],
|
|
@@ -10730,13 +10730,10 @@ function validateTeamWriteInput(input, cfg) {
|
|
|
10730
10730
|
if (maxBudget === void 0) {
|
|
10731
10731
|
return { ok: false, error: "max_budget is required" };
|
|
10732
10732
|
}
|
|
10733
|
-
if (cfg.maxBudgetCeiling === void 0) {
|
|
10734
|
-
return { ok: false, error: "team budget ceiling is not configured (litellm.teamAdmin.maxBudgetCeiling)" };
|
|
10735
|
-
}
|
|
10736
10733
|
if (maxBudget > cfg.maxBudgetCeiling) {
|
|
10737
10734
|
return { ok: false, error: `max_budget $${maxBudget} exceeds the ceiling $${cfg.maxBudgetCeiling}` };
|
|
10738
10735
|
}
|
|
10739
|
-
} else if (maxBudget !== void 0 &&
|
|
10736
|
+
} else if (maxBudget !== void 0 && maxBudget > cfg.maxBudgetCeiling) {
|
|
10740
10737
|
return { ok: false, error: `max_budget $${maxBudget} exceeds the ceiling $${cfg.maxBudgetCeiling}` };
|
|
10741
10738
|
}
|
|
10742
10739
|
let budgetDuration = input.budget_duration;
|
|
@@ -10797,7 +10794,7 @@ function validateTeamPatchInput(input, cfg) {
|
|
|
10797
10794
|
if (!Number.isFinite(input.max_budget) || input.max_budget <= 0) {
|
|
10798
10795
|
return { ok: false, error: "max_budget must be a positive number" };
|
|
10799
10796
|
}
|
|
10800
|
-
if (
|
|
10797
|
+
if (input.max_budget > cfg.maxBudgetCeiling) {
|
|
10801
10798
|
return { ok: false, error: `max_budget $${input.max_budget} exceeds the ceiling $${cfg.maxBudgetCeiling}` };
|
|
10802
10799
|
}
|
|
10803
10800
|
result.max_budget = input.max_budget;
|
|
@@ -10830,6 +10827,25 @@ function validateTeamPatchInput(input, cfg) {
|
|
|
10830
10827
|
|
|
10831
10828
|
// src/router.ts
|
|
10832
10829
|
var teamCreateInFlight = /* @__PURE__ */ new Map();
|
|
10830
|
+
var TEAM_FETCH_RETRY_DELAYS_MS = [100, 300, 900];
|
|
10831
|
+
function isRetryableTeamFetchError(err) {
|
|
10832
|
+
if (err instanceof LiteLLMUpstreamError) {
|
|
10833
|
+
return err.status >= 500;
|
|
10834
|
+
}
|
|
10835
|
+
return true;
|
|
10836
|
+
}
|
|
10837
|
+
async function withTeamFetchRetry(fn, delaysMs = TEAM_FETCH_RETRY_DELAYS_MS) {
|
|
10838
|
+
for (let attempt = 0; ; attempt++) {
|
|
10839
|
+
try {
|
|
10840
|
+
return await fn();
|
|
10841
|
+
} catch (err) {
|
|
10842
|
+
if (attempt >= delaysMs.length || !isRetryableTeamFetchError(err)) {
|
|
10843
|
+
throw err;
|
|
10844
|
+
}
|
|
10845
|
+
await new Promise((resolve) => setTimeout(resolve, delaysMs[attempt]));
|
|
10846
|
+
}
|
|
10847
|
+
}
|
|
10848
|
+
}
|
|
10833
10849
|
async function createRouter(options) {
|
|
10834
10850
|
const { config, logger, auth, discovery, permissions } = options;
|
|
10835
10851
|
const baseUrl = config.getString("litellm.baseUrl");
|
|
@@ -10867,7 +10883,7 @@ async function createRouter(options) {
|
|
|
10867
10883
|
keyGeneration: { allowUnlimitedBudget, teamRequired },
|
|
10868
10884
|
teamManagement: {
|
|
10869
10885
|
enabled: teamMgmtEnabled,
|
|
10870
|
-
maxBudgetCeiling: teamAdminCfg.maxBudgetCeiling
|
|
10886
|
+
maxBudgetCeiling: teamAdminCfg.maxBudgetCeiling,
|
|
10871
10887
|
allowUnlimitedBudget: teamAdminCfg.allowUnlimitedBudget,
|
|
10872
10888
|
objectPermissionsEnabled: objectPermsEnabled
|
|
10873
10889
|
}
|
|
@@ -11263,8 +11279,8 @@ async function createRouter(options) {
|
|
|
11263
11279
|
}
|
|
11264
11280
|
const teams = await Promise.all(
|
|
11265
11281
|
userInfo.teams.map(
|
|
11266
|
-
(teamId) => client.getTeamInfo(teamId).catch((err) => {
|
|
11267
|
-
logger.warn(`Failed to fetch team ${teamId}: ${err.message}`);
|
|
11282
|
+
(teamId) => withTeamFetchRetry(() => client.getTeamInfo(teamId)).catch((err) => {
|
|
11283
|
+
logger.warn(`Failed to fetch team ${teamId} after retries: ${err.message}`);
|
|
11268
11284
|
return null;
|
|
11269
11285
|
})
|
|
11270
11286
|
)
|
|
@@ -11497,7 +11513,7 @@ async function createRouter(options) {
|
|
|
11497
11513
|
}
|
|
11498
11514
|
let existing;
|
|
11499
11515
|
try {
|
|
11500
|
-
existing = await client.getTeamInfo(teamId);
|
|
11516
|
+
existing = await withTeamFetchRetry(() => client.getTeamInfo(teamId));
|
|
11501
11517
|
} catch (err) {
|
|
11502
11518
|
if (err instanceof LiteLLMUpstreamError && err.status === 404) {
|
|
11503
11519
|
res.status(404).json({ error: "Team not found" });
|
|
@@ -11611,7 +11627,7 @@ async function createRouter(options) {
|
|
|
11611
11627
|
member: litellmUserId,
|
|
11612
11628
|
owningGroup
|
|
11613
11629
|
});
|
|
11614
|
-
const updated = await client.getTeamInfo(teamId);
|
|
11630
|
+
const updated = await withTeamFetchRetry(() => client.getTeamInfo(teamId));
|
|
11615
11631
|
res.json(updated);
|
|
11616
11632
|
} catch (err) {
|
|
11617
11633
|
sendTeamError(err, res);
|
|
@@ -11642,7 +11658,7 @@ async function createRouter(options) {
|
|
|
11642
11658
|
member: litellmUserId,
|
|
11643
11659
|
owningGroup
|
|
11644
11660
|
});
|
|
11645
|
-
const updated = await client.getTeamInfo(teamId);
|
|
11661
|
+
const updated = await withTeamFetchRetry(() => client.getTeamInfo(teamId));
|
|
11646
11662
|
res.json(updated);
|
|
11647
11663
|
} catch (err) {
|
|
11648
11664
|
sendTeamError(err, res);
|