@acarmisc/backstage-plugin-litellm-backend 0.20.0 → 0.22.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
@@ -216,6 +216,12 @@ export interface Config {
216
216
  */
217
217
  maxBudget?: number;
218
218
 
219
+ /**
220
+ * Reset period of maxBudget in LiteLLM format (e.g. "30d"). Unset, maxBudget
221
+ * covers the whole life of the key.
222
+ */
223
+ budgetDuration?: string;
224
+
219
225
  /**
220
226
  * When true a team must be supplied and the user must belong to it.
221
227
  * @default false
package/dist/index.cjs.js CHANGED
@@ -9351,6 +9351,7 @@ function readOpencodeConfig(config) {
9351
9351
  enabled,
9352
9352
  keyDuration: config.getOptionalString("litellm.opencode.keyDuration") ?? "30d",
9353
9353
  maxBudget: config.getOptionalNumber("litellm.opencode.maxBudget") ?? 50,
9354
+ budgetDuration: config.getOptionalString("litellm.opencode.budgetDuration"),
9354
9355
  requireTeam: config.getOptionalBoolean("litellm.opencode.requireTeam") ?? false,
9355
9356
  metadata: config.getOptional(
9356
9357
  "litellm.opencode.metadata"
@@ -10636,6 +10637,8 @@ function registerOpencodeRoutes(router, ctx) {
10636
10637
  const reusable = existing.find(
10637
10638
  (k) => k.key_alias === alias && !k.blocked && k.user_id === userId
10638
10639
  );
10640
+ const teamPerm = teamId ? (await client.getTeamInfo(teamId).catch(() => void 0))?.object_permission : void 0;
10641
+ const mcp = teamPerm?.mcp_servers?.length || teamPerm?.mcp_access_groups?.length ? { mcp_servers: teamPerm.mcp_servers ?? [], mcp_access_groups: teamPerm.mcp_access_groups ?? [] } : void 0;
10639
10642
  const mintNewKey = async () => {
10640
10643
  const profile = await resolveUserProfile(
10641
10644
  tokenEntityRef,
@@ -10647,6 +10650,7 @@ function registerOpencodeRoutes(router, ctx) {
10647
10650
  alias,
10648
10651
  duration: opencodeCfg.keyDuration,
10649
10652
  max_budget: opencodeCfg.maxBudget,
10653
+ ...opencodeCfg.budgetDuration && { budget_duration: opencodeCfg.budgetDuration },
10650
10654
  team_id: teamId,
10651
10655
  metadata: {
10652
10656
  ...opencodeCfg.metadata,
@@ -10655,7 +10659,8 @@ function registerOpencodeRoutes(router, ctx) {
10655
10659
  ...profile.email && { created_by_email: profile.email },
10656
10660
  ...teamId && { opencode_team: teamId }
10657
10661
  },
10658
- user_id: userId
10662
+ user_id: userId,
10663
+ ...mcp && { object_permission: mcp }
10659
10664
  });
10660
10665
  return result.key;
10661
10666
  };
@@ -10666,6 +10671,7 @@ function registerOpencodeRoutes(router, ctx) {
10666
10671
  try {
10667
10672
  key = (await client.regenerateKey(keyHashOrId)).key;
10668
10673
  rotated = true;
10674
+ if (key && mcp) await client.updateKey({ key, object_permission: mcp });
10669
10675
  } catch (err) {
10670
10676
  const unsupported = err instanceof LiteLLMUpstreamError && ([400, 404, 405, 501].includes(err.status) || /enterprise|premium/i.test(err.message));
10671
10677
  if (!unsupported) throw err;
@@ -10681,14 +10687,15 @@ function registerOpencodeRoutes(router, ctx) {
10681
10687
  res.status(502).json({ error: "LiteLLM returned no key material" });
10682
10688
  return;
10683
10689
  }
10690
+ logger.info("opencode.connect", { userId, team: teamId ?? null, rotated });
10691
+ if (req.is("application/json")) {
10692
+ res.set("Cache-Control", "no-store");
10693
+ res.json({ key, team: teamId ?? null });
10694
+ return;
10695
+ }
10684
10696
  const url = new URL(redirectUri);
10685
10697
  url.searchParams.set("key", key);
10686
10698
  if (teamId) url.searchParams.set("team", teamId);
10687
- logger.info("opencode.connect", {
10688
- userId,
10689
- team: teamId ?? null,
10690
- rotated
10691
- });
10692
10699
  res.redirect(302, url.href);
10693
10700
  } catch (error) {
10694
10701
  if (error instanceof ProvisioningError) {