@acarmisc/backstage-plugin-litellm-backend 0.17.1 → 0.17.3
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/index.cjs.js +64 -21
- package/dist/index.cjs.js.map +3 -3
- package/dist/routes/bridge.js +43 -4
- package/package.json +1 -1
package/dist/routes/bridge.js
CHANGED
|
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.registerBridgeRoutes = registerBridgeRoutes;
|
|
4
4
|
const provisioning_1 = require("../provisioning");
|
|
5
5
|
const bridge_1 = require("../bridge");
|
|
6
|
+
const backstage_plugin_litellm_common_1 = require("@acarmisc/backstage-plugin-litellm-common");
|
|
6
7
|
const keyService_1 = require("../services/keyService");
|
|
7
8
|
const errors_1 = require("../errors");
|
|
8
|
-
const
|
|
9
|
+
const backstage_plugin_litellm_common_2 = require("@acarmisc/backstage-plugin-litellm-common");
|
|
9
10
|
function registerBridgeRoutes(router, ctx, bridgeOpts) {
|
|
10
11
|
const { client, logger, userIdDomain, provisioningEnabled, provisioningDefaults, roleConfigs, allowUnlimitedBudget, teamRequired, keyValidationConfig, } = ctx;
|
|
11
12
|
const { config } = bridgeOpts;
|
|
12
|
-
const generateKeyInputSchema = (0,
|
|
13
|
+
const generateKeyInputSchema = (0, backstage_plugin_litellm_common_2.createGenerateKeyInputSchema)(ctx.keyValidationConfig);
|
|
13
14
|
// ---------------------------------------------------------------------------
|
|
14
15
|
// Bridge endpoints (CLI / Abby)
|
|
15
16
|
//
|
|
@@ -91,6 +92,13 @@ function registerBridgeRoutes(router, ctx, bridgeOpts) {
|
|
|
91
92
|
return;
|
|
92
93
|
}
|
|
93
94
|
const input = parseResult.data;
|
|
95
|
+
// CLI clients don't know the budget policy. When unlimited budgets are
|
|
96
|
+
// not allowed and the caller sent no max_budget, fall back to the
|
|
97
|
+
// provisioning default instead of rejecting the mint. An explicit
|
|
98
|
+
// value (including null) is left alone and validated as usual.
|
|
99
|
+
if (!allowUnlimitedBudget && input.max_budget === undefined) {
|
|
100
|
+
input.max_budget = provisioningDefaults.maxBudget;
|
|
101
|
+
}
|
|
94
102
|
// ── Resolve user identity from verified claims ───────────────────────
|
|
95
103
|
const userId = (0, bridge_1.resolveBridgeUserId)(claims, bridgeIdentity);
|
|
96
104
|
// ── Create key via unified service ──────────────────────────────────
|
|
@@ -118,11 +126,42 @@ function registerBridgeRoutes(router, ctx, bridgeOpts) {
|
|
|
118
126
|
handleBridgeError(error, res);
|
|
119
127
|
}
|
|
120
128
|
});
|
|
129
|
+
// Caller's LiteLLM identity: user id + team memberships. Lets CLI clients
|
|
130
|
+
// offer a team picker and mint keys under a valid team.
|
|
131
|
+
router.get('/bridge/user/info', async (req, res) => {
|
|
132
|
+
try {
|
|
133
|
+
const claims = await requireClaims(req);
|
|
134
|
+
const user = await (0, bridge_1.getOrProvisionUserFromClaims)(client, claims, provisioningEnabled, provisioningDefaults, logger, bridgeIdentity);
|
|
135
|
+
res.json({ user_id: user.user_id, teams: user.teams ?? [] });
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
handleBridgeError(error, res);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
// Model catalogue. With ?team_id=X the list is narrowed to the models the
|
|
142
|
+
// team may use (its `models` plus access groups); the caller must belong
|
|
143
|
+
// to that team. Without it the full catalogue is returned, as before.
|
|
121
144
|
router.get('/bridge/models', async (req, res) => {
|
|
122
145
|
try {
|
|
123
|
-
await requireClaims(req);
|
|
146
|
+
const claims = await requireClaims(req);
|
|
147
|
+
const teamId = typeof req.query.team_id === 'string' ? req.query.team_id : '';
|
|
124
148
|
const models = await client.listModels();
|
|
125
|
-
|
|
149
|
+
if (!teamId) {
|
|
150
|
+
res.json(models);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const user = await (0, bridge_1.getOrProvisionUserFromClaims)(client, claims, provisioningEnabled, provisioningDefaults, logger, bridgeIdentity);
|
|
154
|
+
if (!(user.teams ?? []).includes(teamId)) {
|
|
155
|
+
res.status(403).json({ error: 'Access denied: team is not one of your teams', team_id: teamId });
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const team = await client.getTeamInfo(teamId);
|
|
159
|
+
const allowed = team.models;
|
|
160
|
+
if (!allowed || allowed.length === 0 || allowed.includes(backstage_plugin_litellm_common_1.ALL_PROXY_MODELS)) {
|
|
161
|
+
res.json(models);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
res.json(models.filter(m => (0, backstage_plugin_litellm_common_1.isModelAllowed)(m, allowed)));
|
|
126
165
|
}
|
|
127
166
|
catch (error) {
|
|
128
167
|
handleBridgeError(error, res);
|