@acarmisc/backstage-plugin-litellm-backend 0.6.1 → 0.7.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/config.d.ts CHANGED
@@ -127,6 +127,27 @@ export interface Config {
127
127
  group?: string;
128
128
  };
129
129
 
130
+ /**
131
+ * Controls for the "Generate New Key" form in the frontend.
132
+ */
133
+ keyGeneration?: {
134
+ /**
135
+ * When true, users can tick an "Unlimited budget" checkbox that skips
136
+ * the max-budget cap entirely. The checkbox is hidden from the form
137
+ * when this is false, so a budget is always required.
138
+ * @default false
139
+ */
140
+ allowUnlimitedBudget?: boolean;
141
+
142
+ /**
143
+ * When true (the default), a team must be selected before a key can
144
+ * be generated. Set to false to let users generate personal,
145
+ * team-less keys.
146
+ * @default true
147
+ */
148
+ teamRequired?: boolean;
149
+ };
150
+
130
151
  bridge?: {
131
152
  /**
132
153
  * When true, mount the /bridge/keys, /bridge/keys (POST), /bridge/models
package/dist/index.cjs.js CHANGED
@@ -511,12 +511,16 @@ var openApiSpec = {
511
511
  "/config": {
512
512
  get: {
513
513
  tags: ["System"],
514
- summary: "Public LiteLLM proxy base URL (for snippet generation)",
514
+ summary: "Public LiteLLM proxy base URL and key-generation form settings",
515
515
  responses: {
516
516
  "200": {
517
- description: "Proxy URL",
517
+ description: "Frontend config",
518
518
  content: { "application/json": { schema: { type: "object", properties: {
519
- baseUrl: { type: "string" }
519
+ baseUrl: { type: "string" },
520
+ keyGeneration: { type: "object", properties: {
521
+ allowUnlimitedBudget: { type: "boolean" },
522
+ teamRequired: { type: "boolean" }
523
+ } }
520
524
  } } } }
521
525
  }
522
526
  }
@@ -2465,6 +2469,8 @@ async function createRouter(options) {
2465
2469
  const { enabled: provisioningEnabled, defaults: provisioningDefaults } = readProvisioningDefaults(config);
2466
2470
  const roleConfigs = readRoleConfigs(config);
2467
2471
  const auditGroup = config.getOptionalString("litellm.audit.group");
2472
+ const allowUnlimitedBudget = config.getOptionalBoolean("litellm.keyGeneration.allowUnlimitedBudget") ?? false;
2473
+ const teamRequired = config.getOptionalBoolean("litellm.keyGeneration.teamRequired") ?? true;
2468
2474
  const catalogClient = new import_catalog_client.CatalogClient({ discoveryApi: discovery });
2469
2475
  if (provisioningEnabled) {
2470
2476
  logger.info(
@@ -2477,7 +2483,10 @@ async function createRouter(options) {
2477
2483
  res.json({ status: "ok", provisioning: provisioningEnabled });
2478
2484
  });
2479
2485
  router.get("/config", (_req, res) => {
2480
- res.json({ baseUrl: publicBaseUrl });
2486
+ res.json({
2487
+ baseUrl: publicBaseUrl,
2488
+ keyGeneration: { allowUnlimitedBudget, teamRequired }
2489
+ });
2481
2490
  });
2482
2491
  router.get("/openapi.json", (_req, res) => {
2483
2492
  res.json(openApiSpec);
@@ -2662,6 +2671,13 @@ async function createRouter(options) {
2662
2671
  res.status(error.status).json(error.body);
2663
2672
  return;
2664
2673
  }
2674
+ if (typeof error.message === "string" && error.message.includes("Invalid duration format") && req.body?.team_id) {
2675
+ res.status(502).json({
2676
+ error: 'LiteLLM rejected the key duration for this team. The team has a "Team Member Key Duration" set in LiteLLM that is not in a valid <number><unit> format (e.g. "30d") and overrides whatever duration is requested. Fix or clear it in LiteLLM under Teams \u2192 this team \u2192 Team Settings, then retry.',
2677
+ teamId: req.body.team_id
2678
+ });
2679
+ return;
2680
+ }
2665
2681
  logger.error("Failed to generate key", error);
2666
2682
  res.status(500).json({ error: error.message });
2667
2683
  }