@acarmisc/backstage-plugin-litellm-backend 0.13.0 → 0.14.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/client.d.ts +18 -1
- package/dist/client.js +54 -0
- package/dist/index.cjs.js +172 -0
- package/dist/index.cjs.js.map +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/opencode.d.ts +30 -0
- package/dist/opencode.js +13 -0
- package/dist/router.js +137 -0
- package/dist/types.cjs.js.map +1 -1
- package/dist/types.d.ts +36 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { litellmPlugin } from './plugin';
|
|
|
2
2
|
export { litellmPlugin as default } from './plugin';
|
|
3
3
|
export { createRouter } from './router';
|
|
4
4
|
export * from './types';
|
|
5
|
-
export { LiteLLMClient } from './client';
|
|
5
|
+
export { LiteLLMClient, normalizeRequestTags } from './client';
|
|
6
6
|
export { resolveUserId, resolveUserProfile, toLiteLLMUserId, getOrProvisionUser, provisionUser, readProvisioningDefaults, readRoleConfigs, applyRoleOverrides, resolveUserRole, ProvisioningError, } from './provisioning';
|
|
7
7
|
export type { BackstageUserProfile } from './provisioning';
|
|
8
8
|
export { readTeamAdminConfig, isTeamManagementEnabled, assertTeamAdmin, validateTeamWriteInput, validateTeamPatchInput, } from './teamAdmin';
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.litellmTeamDeletePermission = exports.litellmTeamMcpManagePermission = exports.litellmTeamKnowledgebaseManagePermission = exports.litellmTeamMembersManagePermission = exports.litellmTeamManagePermission = exports.litellmTeamCreatePermission = exports.litellmAuditReadPermission = exports.litellmKeyManagePermission = exports.litellmKeyRevokePermission = exports.litellmKeyCreatePermission = exports.litellmPermissions = exports.bridgeGenerateKey = exports.bridgeListKeys = exports.getOrProvisionUserFromClaims = exports.resolveBridgeUserId = exports.readBridgeConfig = exports.newDefaultVerifier = exports.KeycloakJWTVerifier = exports.teamBudgetStatusFor = exports.redactTeamUsage = exports.redactTeamBudget = exports.readTeamBudgetVisibility = exports.validateTeamPatchInput = exports.validateTeamWriteInput = exports.assertTeamAdmin = exports.isTeamManagementEnabled = exports.readTeamAdminConfig = exports.ProvisioningError = exports.resolveUserRole = exports.applyRoleOverrides = exports.readRoleConfigs = exports.readProvisioningDefaults = exports.provisionUser = exports.getOrProvisionUser = exports.toLiteLLMUserId = exports.resolveUserProfile = exports.resolveUserId = exports.LiteLLMClient = exports.createRouter = exports.default = exports.litellmPlugin = void 0;
|
|
17
|
+
exports.litellmTeamDeletePermission = exports.litellmTeamMcpManagePermission = exports.litellmTeamKnowledgebaseManagePermission = exports.litellmTeamMembersManagePermission = exports.litellmTeamManagePermission = exports.litellmTeamCreatePermission = exports.litellmAuditReadPermission = exports.litellmKeyManagePermission = exports.litellmKeyRevokePermission = exports.litellmKeyCreatePermission = exports.litellmPermissions = exports.bridgeGenerateKey = exports.bridgeListKeys = exports.getOrProvisionUserFromClaims = exports.resolveBridgeUserId = exports.readBridgeConfig = exports.newDefaultVerifier = exports.KeycloakJWTVerifier = exports.teamBudgetStatusFor = exports.redactTeamUsage = exports.redactTeamBudget = exports.readTeamBudgetVisibility = exports.validateTeamPatchInput = exports.validateTeamWriteInput = exports.assertTeamAdmin = exports.isTeamManagementEnabled = exports.readTeamAdminConfig = exports.ProvisioningError = exports.resolveUserRole = exports.applyRoleOverrides = exports.readRoleConfigs = exports.readProvisioningDefaults = exports.provisionUser = exports.getOrProvisionUser = exports.toLiteLLMUserId = exports.resolveUserProfile = exports.resolveUserId = exports.normalizeRequestTags = exports.LiteLLMClient = exports.createRouter = exports.default = exports.litellmPlugin = void 0;
|
|
18
18
|
var plugin_1 = require("./plugin");
|
|
19
19
|
Object.defineProperty(exports, "litellmPlugin", { enumerable: true, get: function () { return plugin_1.litellmPlugin; } });
|
|
20
20
|
var plugin_2 = require("./plugin");
|
|
@@ -24,6 +24,7 @@ Object.defineProperty(exports, "createRouter", { enumerable: true, get: function
|
|
|
24
24
|
__exportStar(require("./types"), exports);
|
|
25
25
|
var client_1 = require("./client");
|
|
26
26
|
Object.defineProperty(exports, "LiteLLMClient", { enumerable: true, get: function () { return client_1.LiteLLMClient; } });
|
|
27
|
+
Object.defineProperty(exports, "normalizeRequestTags", { enumerable: true, get: function () { return client_1.normalizeRequestTags; } });
|
|
27
28
|
var provisioning_1 = require("./provisioning");
|
|
28
29
|
Object.defineProperty(exports, "resolveUserId", { enumerable: true, get: function () { return provisioning_1.resolveUserId; } });
|
|
29
30
|
Object.defineProperty(exports, "resolveUserProfile", { enumerable: true, get: function () { return provisioning_1.resolveUserProfile; } });
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Config } from '@backstage/config';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for the OpenCode SSO-connect integration (litellm.opencode.*).
|
|
4
|
+
*
|
|
5
|
+
* The connect flow is served by the opencode-portal-auth plugin client-side:
|
|
6
|
+
* the user runs /connect in OpenCode, a browser opens
|
|
7
|
+
* GET {baseUrl}/api/litellm/opencode/connect?team=...&redirect_uri=...
|
|
8
|
+
* and this backend generates (or reuses) a LiteLLM virtual key bound to the
|
|
9
|
+
* signed-in Backstage user and, optionally, one of their teams, then 302s
|
|
10
|
+
* back to the local OpenCode callback listener.
|
|
11
|
+
*/
|
|
12
|
+
export interface OpencodeConfig {
|
|
13
|
+
/** Route is mounted only when true. Default false. */
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Default duration for freshly generated keys, in LiteLLM format
|
|
17
|
+
* (e.g. "30d"). Users can re-connect to rotate. Default '30d'.
|
|
18
|
+
*/
|
|
19
|
+
keyDuration: string;
|
|
20
|
+
/** Default max budget (USD) for keys created via the connect flow. Default 50. */
|
|
21
|
+
maxBudget: number;
|
|
22
|
+
/**
|
|
23
|
+
* When true, a team query parameter must reference a team the user is a
|
|
24
|
+
* member of (or manage); otherwise the key is personal-only.
|
|
25
|
+
*/
|
|
26
|
+
requireTeam: boolean;
|
|
27
|
+
/** Extra metadata stamped on keys created via this flow. */
|
|
28
|
+
metadata: Record<string, string>;
|
|
29
|
+
}
|
|
30
|
+
export declare function readOpencodeConfig(config: Config): OpencodeConfig;
|
package/dist/opencode.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readOpencodeConfig = readOpencodeConfig;
|
|
4
|
+
function readOpencodeConfig(config) {
|
|
5
|
+
const enabled = config.getOptionalBoolean('litellm.opencode.enabled') ?? false;
|
|
6
|
+
return {
|
|
7
|
+
enabled,
|
|
8
|
+
keyDuration: config.getOptionalString('litellm.opencode.keyDuration') ?? '30d',
|
|
9
|
+
maxBudget: config.getOptionalNumber('litellm.opencode.maxBudget') ?? 50,
|
|
10
|
+
requireTeam: config.getOptionalBoolean('litellm.opencode.requireTeam') ?? false,
|
|
11
|
+
metadata: config.getOptional('litellm.opencode.metadata') ?? {},
|
|
12
|
+
};
|
|
13
|
+
}
|
package/dist/router.js
CHANGED
|
@@ -46,6 +46,7 @@ const bridge_1 = require("./bridge");
|
|
|
46
46
|
const permissions_1 = require("./permissions");
|
|
47
47
|
const teamAdmin_1 = require("./teamAdmin");
|
|
48
48
|
const teamBudgetVisibility_1 = require("./teamBudgetVisibility");
|
|
49
|
+
const opencode_1 = require("./opencode");
|
|
49
50
|
const teamCreateInFlight = new Map();
|
|
50
51
|
/** Backoff schedule for `withTeamFetchRetry` — 3 retries over ~1.3s total. */
|
|
51
52
|
const TEAM_FETCH_RETRY_DELAYS_MS = [100, 300, 900];
|
|
@@ -85,6 +86,24 @@ async function withTeamFetchRetry(fn, delaysMs = TEAM_FETCH_RETRY_DELAYS_MS) {
|
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Only loopback http://localhost:<port>/callback redirect URIs are accepted —
|
|
91
|
+
* the OpenCode plugin runs its callback listener on 127.0.0.1. This
|
|
92
|
+
* keeps the flow from being usable as an open redirect.
|
|
93
|
+
*/
|
|
94
|
+
function isValidRedirectUri(uri) {
|
|
95
|
+
if (!uri)
|
|
96
|
+
return false;
|
|
97
|
+
try {
|
|
98
|
+
const url = new URL(uri);
|
|
99
|
+
return (url.protocol === 'http:' &&
|
|
100
|
+
(url.hostname === 'localhost' || url.hostname === '127.0.0.1') &&
|
|
101
|
+
url.pathname === '/callback');
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
88
107
|
async function createRouter(options) {
|
|
89
108
|
const { config, logger, auth, discovery, permissions } = options;
|
|
90
109
|
const baseUrl = config.getString('litellm.baseUrl');
|
|
@@ -104,6 +123,7 @@ async function createRouter(options) {
|
|
|
104
123
|
const objectPermsEnabled = (0, teamAdmin_1.isObjectPermissionsEnabled)(config);
|
|
105
124
|
const teamAdminCfg = (0, teamAdmin_1.readTeamAdminConfig)(config);
|
|
106
125
|
const teamBudgetVisibility = (0, teamBudgetVisibility_1.readTeamBudgetVisibility)(config);
|
|
126
|
+
const opencodeCfg = (0, opencode_1.readOpencodeConfig)(config);
|
|
107
127
|
const catalogClient = options.catalogClient ?? new catalog_client_1.CatalogClient({ discoveryApi: discovery });
|
|
108
128
|
if (provisioningEnabled) {
|
|
109
129
|
logger.info(`LiteLLM auto-provisioning enabled — defaults: budget=$${provisioningDefaults.maxBudget}/${provisioningDefaults.budgetDuration}, models=${provisioningDefaults.models.length
|
|
@@ -131,6 +151,7 @@ async function createRouter(options) {
|
|
|
131
151
|
res.json({
|
|
132
152
|
baseUrl: publicBaseUrl,
|
|
133
153
|
keyGeneration: { allowUnlimitedBudget, teamRequired },
|
|
154
|
+
opencode: { enabled: opencodeCfg.enabled },
|
|
134
155
|
teamManagement: {
|
|
135
156
|
enabled: teamMgmtEnabled,
|
|
136
157
|
maxBudgetCeiling: teamAdminCfg.maxBudgetCeiling,
|
|
@@ -396,6 +417,122 @@ async function createRouter(options) {
|
|
|
396
417
|
res.status(500).json({ error: error.message });
|
|
397
418
|
}
|
|
398
419
|
});
|
|
420
|
+
// ── OpenCode SSO-connect ─────────────────────────────────────────────────
|
|
421
|
+
//
|
|
422
|
+
// Client side: the opencode-portal-auth plugin. Handshake contract (see
|
|
423
|
+
// that package's README):
|
|
424
|
+
//
|
|
425
|
+
// GET /opencode/connect?team=<id>&redirect_uri=http://localhost:<port>/callback
|
|
426
|
+
// → (SSO-authenticated) generate/reuse a virtual key bound to the
|
|
427
|
+
// user and optional team → 302 {redirect_uri}?key=<api-key>
|
|
428
|
+
//
|
|
429
|
+
// Mounted only when litellm.opencode.enabled is true. Key creation is
|
|
430
|
+
// gated by the same litellmKeyCreatePermission as POST /keys/generate.
|
|
431
|
+
if (opencodeCfg.enabled) {
|
|
432
|
+
logger.info(`OpenCode connect endpoint enabled — duration=${opencodeCfg.keyDuration}, maxBudget=$${opencodeCfg.maxBudget}`);
|
|
433
|
+
router.get('/opencode/connect', async (req, res) => {
|
|
434
|
+
try {
|
|
435
|
+
// The request comes from the browser (user session), so SSO
|
|
436
|
+
// auth applies exactly like for any other UI route.
|
|
437
|
+
const tokenEntityRef = await (0, provisioning_1.resolveUserId)(req, auth);
|
|
438
|
+
if (!tokenEntityRef) {
|
|
439
|
+
res.status(401).json({ error: 'Authentication required' });
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
const redirectUri = req.query.redirect_uri;
|
|
443
|
+
if (!isValidRedirectUri(redirectUri)) {
|
|
444
|
+
res.status(400).json({
|
|
445
|
+
error: 'Invalid redirect_uri — expected http://localhost:<port>/callback',
|
|
446
|
+
});
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
if (!(await assertPermission(req, permissions_1.litellmKeyCreatePermission))) {
|
|
450
|
+
sendPermissionDenied(res, permissions_1.litellmKeyCreatePermission);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
const userId = (0, provisioning_1.toLiteLLMUserId)(tokenEntityRef, userIdDomain);
|
|
454
|
+
const userInfo = await (0, provisioning_1.getOrProvisionUser)(client, tokenEntityRef, userId, provisioningEnabled, provisioningDefaults, roleConfigs, catalogClient, auth, logger);
|
|
455
|
+
// Optional team binding: must be one of the user's own teams so
|
|
456
|
+
// the connect flow can never mint a key billed to someone else.
|
|
457
|
+
const teamId = req.query.team;
|
|
458
|
+
if (teamId) {
|
|
459
|
+
const userTeams = userInfo?.teams ?? [];
|
|
460
|
+
if (!userTeams.includes(teamId)) {
|
|
461
|
+
res.status(403).json({
|
|
462
|
+
error: 'Access denied: team is not one of your teams',
|
|
463
|
+
team: teamId,
|
|
464
|
+
});
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
else if (opencodeCfg.requireTeam) {
|
|
469
|
+
res.status(400).json({ error: 'A team is required for this connection' });
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
// Alias is stable per user+team so re-connecting rotates the same
|
|
473
|
+
// logical key slot instead of accumulating duplicates. LiteLLM
|
|
474
|
+
// rejects duplicate aliases, so on conflict we look up the existing
|
|
475
|
+
// key and reuse it (the user gets a working connection either way).
|
|
476
|
+
const alias = teamId
|
|
477
|
+
? `opencode-${userId}-${teamId}`
|
|
478
|
+
: `opencode-${userId}`;
|
|
479
|
+
const existing = await client
|
|
480
|
+
.listKeys(userId)
|
|
481
|
+
.catch(() => []);
|
|
482
|
+
// Reuse a healthy existing key for this slot rather than failing
|
|
483
|
+
// on the alias collision LiteLLM would raise. Blocked keys are
|
|
484
|
+
// skipped so a blocked slot can be recovered by re-connecting.
|
|
485
|
+
const reusable = existing.find(k => k.key_alias === alias &&
|
|
486
|
+
!k.blocked &&
|
|
487
|
+
k.user_id === userId);
|
|
488
|
+
let key;
|
|
489
|
+
if (reusable?.token ?? reusable?.key) {
|
|
490
|
+
key = reusable.token ?? reusable.key;
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
const profile = await (0, provisioning_1.resolveUserProfile)(tokenEntityRef, catalogClient, auth, logger);
|
|
494
|
+
const result = await client.generateKey({
|
|
495
|
+
alias,
|
|
496
|
+
duration: opencodeCfg.keyDuration,
|
|
497
|
+
max_budget: opencodeCfg.maxBudget,
|
|
498
|
+
team_id: teamId,
|
|
499
|
+
metadata: {
|
|
500
|
+
...opencodeCfg.metadata,
|
|
501
|
+
created_via: 'opencode-connect',
|
|
502
|
+
created_by_backstage_user: tokenEntityRef,
|
|
503
|
+
...(profile.email && { created_by_email: profile.email }),
|
|
504
|
+
...(teamId && { opencode_team: teamId }),
|
|
505
|
+
},
|
|
506
|
+
user_id: userId,
|
|
507
|
+
});
|
|
508
|
+
if (!result.key) {
|
|
509
|
+
res.status(502).json({ error: 'LiteLLM returned no key material' });
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
key = result.key;
|
|
513
|
+
}
|
|
514
|
+
const url = new URL(redirectUri);
|
|
515
|
+
url.searchParams.set('key', key);
|
|
516
|
+
if (teamId)
|
|
517
|
+
url.searchParams.set('team', teamId);
|
|
518
|
+
logger.info({
|
|
519
|
+
action: 'opencode.connect',
|
|
520
|
+
userId,
|
|
521
|
+
team: teamId ?? null,
|
|
522
|
+
reused: Boolean(reusable?.token ?? reusable?.key),
|
|
523
|
+
});
|
|
524
|
+
res.redirect(302, url.href);
|
|
525
|
+
}
|
|
526
|
+
catch (error) {
|
|
527
|
+
if (error instanceof provisioning_1.ProvisioningError) {
|
|
528
|
+
res.status(error.status).json(error.body);
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
logger.error('OpenCode connect failed', error);
|
|
532
|
+
res.status(500).json({ error: error.message });
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
}
|
|
399
536
|
router.post('/keys/:keyId/update', async (req, res) => {
|
|
400
537
|
try {
|
|
401
538
|
const { keyId } = req.params;
|
package/dist/types.cjs.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/types.ts"],
|
|
4
|
-
"sourcesContent": ["export interface UserInfo {\n user_id: string;\n user_email?: string;\n email?: string;\n teams?: string[];\n models?: string[];\n max_budget?: number;\n spend?: number;\n current_spend?: number;\n soft_limit?: number;\n hard_limit?: number;\n /** Spend-reset period for max_budget, e.g. \"30d\". */\n budget_duration?: string;\n /** Backstage-computed: true when the user is a member of litellm.audit.group */\n can_view_audit?: boolean;\n}\n\nexport interface TeamMember {\n user_id: string;\n user_email?: string;\n role: 'admin' | 'user';\n}\n\nexport interface TeamObjectPermission {\n /** Vector store ids/names attached to the team. */\n vector_stores?: string[];\n /** MCP server ids/names attached to the team. */\n mcp_servers?: string[];\n /** MCP access group names attached to the team. */\n mcp_access_groups?: string[];\n}\n\nexport interface TeamInfo {\n team_id: string;\n team_alias?: string;\n max_budget?: number;\n /** Spend-reset period for max_budget, e.g. \"30d\". */\n budget_duration?: string;\n spend: number;\n /**\n * Share of max_budget consumed (0-100), present only on redacted records.\n * Set by the backend when litellm.display.hideTeamBudgetFor* is enabled so\n * clients can render the consumption level without dollar amounts.\n */\n budget_pct?: number;\n /** ok | near (>=80%) | over (>=100%), present only on redacted records. */\n budget_status?: 'ok' | 'near' | 'over';\n /** True when max_budget/spend were stripped by budget hiding. */\n budget_hidden?: boolean;\n members_with_roles?: TeamMember[];\n models?: string[];\n tpm_limit?: number;\n rpm_limit?: number;\n /** Arbitrary metadata stored on the team record. */\n metadata?: Record<string, unknown>;\n /** Knowledge bases (vector stores) and MCP servers attached to the team. */\n object_permission?: TeamObjectPermission;\n /** Whether the team is blocked/deactivated. */\n blocked?: boolean;\n /** Max budget available to individual team members (if set per-member). */\n team_member_budget?: number;\n}\n\nexport interface CreateTeamRequest {\n team_alias: string;\n models?: string[];\n max_budget?: number;\n budget_duration?: string;\n tpm_limit?: number;\n rpm_limit?: number;\n metadata?: Record<string, unknown>;\n object_permission?: TeamObjectPermission;\n}\n\nexport interface UpdateTeamRequest extends Partial<CreateTeamRequest> {\n team_id: string;\n blocked?: boolean;\n}\n\nexport interface CreateTeamResponse {\n team_id: string;\n team_alias?: string;\n}\n\nexport interface VirtualKey {\n key: string;\n token: string;\n key_alias?: string;\n created_at: string;\n expires_at?: string;\n spend: number;\n max_budget?: number;\n budget_duration?: string;\n tpm_limit?: number;\n rpm_limit?: number;\n models?: string[];\n user_id?: string;\n blocked?: boolean;\n}\n\n/**\n * Shape of a single entry inside LiteLLM's `/user/info` `keys` array.\n * Differs from VirtualKey: uses `expires` (not `expires_at`), exposes\n * both a hashed `token` and a masked `key_name`, and fields are nullable\n * rather than optional.\n */\nexport interface LiteLLMUserKey {\n token: string;\n key_name?: string;\n key_alias?: string | null;\n spend?: number;\n expires?: string | null;\n models?: string[];\n tpm_limit?: number | null;\n rpm_limit?: number | null;\n max_budget?: number | null;\n budget_duration?: string | null;\n user_id?: string | null;\n team_id?: string | null;\n created_at: string;\n blocked?: boolean | null;\n}\n\nexport interface ModelInfo {\n model_name: string;\n mode: string;\n supports_function_calling?: boolean;\n supports_vision?: boolean;\n input_cost_per_token?: number;\n output_cost_per_token?: number;\n max_input_tokens?: number;\n max_output_tokens?: number;\n /** 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. */\n access_groups?: string[];\n}\n\nexport interface UsageModelBreakdown {\n total_spend: number;\n total_tokens: number;\n prompt_tokens: number;\n completion_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n}\n\nexport interface UsageKeyBreakdown {\n key_alias?: string;\n team_id?: string | null;\n models: string[];\n total_spend: number;\n total_tokens: number;\n prompt_tokens: number;\n completion_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n}\n\nexport interface UsageDailyPoint {\n date: string;\n spend: number;\n total_tokens: number;\n prompt_tokens: number;\n completion_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n}\n\nexport interface UsageDailyModelPoint {\n date: string;\n model: string;\n spend: number;\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n}\n\nexport interface UsageMetrics {\n total_spend: number;\n total_tokens: number;\n prompt_tokens: number;\n completion_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n usage_by_model: Record<string, UsageModelBreakdown>;\n usage_by_key: Record<string, UsageKeyBreakdown>;\n daily_usage: UsageDailyPoint[];\n daily_by_model: UsageDailyModelPoint[];\n}\n\nexport interface GenerateKeyRequest {\n alias?: string;\n models?: string[];\n duration?: string;\n max_budget?: number;\n tpm_limit?: number;\n rpm_limit?: number;\n user_id?: string;\n team_id?: string;\n key_type?: string;\n metadata?: Record<string, string>;\n}\n\nexport interface UpdateKeyRequest {\n key: string;\n key_alias?: string;\n models?: string[];\n max_budget?: number;\n tpm_limit?: number;\n rpm_limit?: number;\n team_id?: string;\n duration?: string;\n}\n\nexport interface GenerateKeyResponse {\n key: string;\n key_alias?: string;\n expires_at?: string;\n max_budget?: number;\n tpm_limit?: number;\n rpm_limit?: number;\n models?: string[];\n}\n\nexport interface DeleteKeyRequest {\n keys: string[];\n}\n\nexport interface LiteLLMConfig {\n baseUrl: string;\n masterKey: string;\n}\n\nexport interface ProvisioningDefaults {\n maxBudget: number;\n budgetDuration: string;\n models: string[];\n teams: string[];\n tpmLimit?: number;\n rpmLimit?: number;\n /**\n * LiteLLM user role applied on /user/new. Defaults to \"internal_user\"\n * which grants self-service Create/Delete/View on the user's own keys.\n * Valid values: proxy_admin, proxy_admin_viewer, internal_user,\n * internal_user_viewer, team.\n */\n userRole?: string;\n metadata: Record<string, string>;\n}\n\nexport interface RoleConfig {\n group: string;\n maxBudget?: number;\n budgetDuration?: string;\n models?: string[];\n teams?: string[];\n tpmLimit?: number;\n rpmLimit?: number;\n userRole?: string;\n metadata?: Record<string, string>;\n}\n\nexport interface CreateUserRequest {\n user_id: string;\n user_email?: string;\n user_alias?: string;\n user_role?: string;\n max_budget?: number;\n budget_duration?: string;\n models?: string[];\n teams?: string[];\n tpm_limit?: number;\n rpm_limit?: number;\n metadata?: Record<string, string>;\n auto_create_key?: boolean;\n}\n\nexport interface CreateUserResponse {\n user_id: string;\n user_email?: string;\n max_budget?: number;\n models?: string[];\n teams?: string[];\n}\n\nexport interface AuditLogEntry {\n id: string;\n updated_at: string;\n changed_by?: string;\n changed_by_api_key?: string;\n action?: string;\n table_name?: string;\n object_id?: string;\n before_value?: Record<string, unknown> | null;\n updated_values?: Record<string, unknown> | null;\n}\n\nexport interface PaginatedAuditLogs {\n audit_logs: AuditLogEntry[];\n total: number;\n page: number;\n page_size: number;\n total_pages: number;\n}\n\nexport interface AuditLogsParams {\n page?: number;\n page_size?: number;\n start_date?: string;\n end_date?: string;\n action?: string;\n table_name?: string;\n changed_by?: string;\n sort_by?: string;\n sort_order?: 'asc' | 'desc';\n}\n"],
|
|
4
|
+
"sourcesContent": ["export interface UserInfo {\n user_id: string;\n user_email?: string;\n email?: string;\n teams?: string[];\n models?: string[];\n max_budget?: number;\n spend?: number;\n current_spend?: number;\n soft_limit?: number;\n hard_limit?: number;\n /** Spend-reset period for max_budget, e.g. \"30d\". */\n budget_duration?: string;\n /** Backstage-computed: true when the user is a member of litellm.audit.group */\n can_view_audit?: boolean;\n}\n\nexport interface TeamMember {\n user_id: string;\n user_email?: string;\n role: 'admin' | 'user';\n}\n\nexport interface TeamObjectPermission {\n /** Vector store ids/names attached to the team. */\n vector_stores?: string[];\n /** MCP server ids/names attached to the team. */\n mcp_servers?: string[];\n /** MCP access group names attached to the team. */\n mcp_access_groups?: string[];\n}\n\nexport interface TeamInfo {\n team_id: string;\n team_alias?: string;\n max_budget?: number;\n /** Spend-reset period for max_budget, e.g. \"30d\". */\n budget_duration?: string;\n spend: number;\n /**\n * Share of max_budget consumed (0-100), present only on redacted records.\n * Set by the backend when litellm.display.hideTeamBudgetFor* is enabled so\n * clients can render the consumption level without dollar amounts.\n */\n budget_pct?: number;\n /** ok | near (>=80%) | over (>=100%), present only on redacted records. */\n budget_status?: 'ok' | 'near' | 'over';\n /** True when max_budget/spend were stripped by budget hiding. */\n budget_hidden?: boolean;\n members_with_roles?: TeamMember[];\n models?: string[];\n tpm_limit?: number;\n rpm_limit?: number;\n /** Arbitrary metadata stored on the team record. */\n metadata?: Record<string, unknown>;\n /** Knowledge bases (vector stores) and MCP servers attached to the team. */\n object_permission?: TeamObjectPermission;\n /** Whether the team is blocked/deactivated. */\n blocked?: boolean;\n /** Max budget available to individual team members (if set per-member). */\n team_member_budget?: number;\n}\n\nexport interface CreateTeamRequest {\n team_alias: string;\n models?: string[];\n max_budget?: number;\n budget_duration?: string;\n tpm_limit?: number;\n rpm_limit?: number;\n metadata?: Record<string, unknown>;\n object_permission?: TeamObjectPermission;\n}\n\nexport interface UpdateTeamRequest extends Partial<CreateTeamRequest> {\n team_id: string;\n blocked?: boolean;\n}\n\nexport interface CreateTeamResponse {\n team_id: string;\n team_alias?: string;\n}\n\nexport interface VirtualKey {\n key: string;\n token: string;\n key_alias?: string;\n created_at: string;\n expires_at?: string;\n spend: number;\n max_budget?: number;\n budget_duration?: string;\n tpm_limit?: number;\n rpm_limit?: number;\n models?: string[];\n user_id?: string;\n blocked?: boolean;\n}\n\n/**\n * Shape of a single entry inside LiteLLM's `/user/info` `keys` array.\n * Differs from VirtualKey: uses `expires` (not `expires_at`), exposes\n * both a hashed `token` and a masked `key_name`, and fields are nullable\n * rather than optional.\n */\nexport interface LiteLLMUserKey {\n token: string;\n key_name?: string;\n key_alias?: string | null;\n spend?: number;\n expires?: string | null;\n models?: string[];\n tpm_limit?: number | null;\n rpm_limit?: number | null;\n max_budget?: number | null;\n budget_duration?: string | null;\n user_id?: string | null;\n team_id?: string | null;\n created_at: string;\n blocked?: boolean | null;\n}\n\nexport interface ModelInfo {\n model_name: string;\n mode: string;\n supports_function_calling?: boolean;\n supports_vision?: boolean;\n input_cost_per_token?: number;\n output_cost_per_token?: number;\n max_input_tokens?: number;\n max_output_tokens?: number;\n /** 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. */\n access_groups?: string[];\n}\n\nexport interface UsageModelBreakdown {\n total_spend: number;\n total_tokens: number;\n prompt_tokens: number;\n completion_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n}\n\nexport interface UsageKeyBreakdown {\n key_alias?: string;\n team_id?: string | null;\n models: string[];\n total_spend: number;\n total_tokens: number;\n prompt_tokens: number;\n completion_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n}\n\nexport interface UsageDailyPoint {\n date: string;\n spend: number;\n total_tokens: number;\n prompt_tokens: number;\n completion_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n}\n\nexport interface UsageDailyModelPoint {\n date: string;\n model: string;\n spend: number;\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n}\n\nexport interface UsageMetrics {\n total_spend: number;\n total_tokens: number;\n prompt_tokens: number;\n completion_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n usage_by_model: Record<string, UsageModelBreakdown>;\n usage_by_key: Record<string, UsageKeyBreakdown>;\n daily_usage: UsageDailyPoint[];\n daily_by_model: UsageDailyModelPoint[];\n}\n\nexport interface GenerateKeyRequest {\n alias?: string;\n models?: string[];\n duration?: string;\n max_budget?: number;\n tpm_limit?: number;\n rpm_limit?: number;\n user_id?: string;\n team_id?: string;\n key_type?: string;\n metadata?: Record<string, string>;\n}\n\nexport interface UpdateKeyRequest {\n key: string;\n key_alias?: string;\n models?: string[];\n max_budget?: number;\n tpm_limit?: number;\n rpm_limit?: number;\n team_id?: string;\n duration?: string;\n}\n\nexport interface GenerateKeyResponse {\n key: string;\n key_alias?: string;\n expires_at?: string;\n max_budget?: number;\n tpm_limit?: number;\n rpm_limit?: number;\n models?: string[];\n}\n\nexport interface DeleteKeyRequest {\n keys: string[];\n}\n\nexport interface LiteLLMConfig {\n baseUrl: string;\n masterKey: string;\n}\n\nexport interface ProvisioningDefaults {\n maxBudget: number;\n budgetDuration: string;\n models: string[];\n teams: string[];\n tpmLimit?: number;\n rpmLimit?: number;\n /**\n * LiteLLM user role applied on /user/new. Defaults to \"internal_user\"\n * which grants self-service Create/Delete/View on the user's own keys.\n * Valid values: proxy_admin, proxy_admin_viewer, internal_user,\n * internal_user_viewer, team.\n */\n userRole?: string;\n metadata: Record<string, string>;\n}\n\nexport interface RoleConfig {\n group: string;\n maxBudget?: number;\n budgetDuration?: string;\n models?: string[];\n teams?: string[];\n tpmLimit?: number;\n rpmLimit?: number;\n userRole?: string;\n metadata?: Record<string, string>;\n}\n\nexport interface CreateUserRequest {\n user_id: string;\n user_email?: string;\n user_alias?: string;\n user_role?: string;\n max_budget?: number;\n budget_duration?: string;\n models?: string[];\n teams?: string[];\n tpm_limit?: number;\n rpm_limit?: number;\n metadata?: Record<string, string>;\n auto_create_key?: boolean;\n}\n\nexport interface CreateUserResponse {\n user_id: string;\n user_email?: string;\n max_budget?: number;\n models?: string[];\n teams?: string[];\n}\n\nexport interface AuditLogEntry {\n id: string;\n updated_at: string;\n changed_by?: string;\n changed_by_api_key?: string;\n action?: string;\n table_name?: string;\n object_id?: string;\n before_value?: Record<string, unknown> | null;\n updated_values?: Record<string, unknown> | null;\n}\n\nexport interface PaginatedAuditLogs {\n audit_logs: AuditLogEntry[];\n total: number;\n page: number;\n page_size: number;\n total_pages: number;\n}\n\n/** One row from LiteLLM's `/spend/logs` (per-request spend log entry). */\nexport interface SpendLogEntry {\n request_id?: string;\n /** ISO timestamp of the call. */\n startTime?: string;\n endTime?: string;\n spend?: number;\n total_tokens?: number;\n prompt_tokens?: number;\n completion_tokens?: number;\n model?: string;\n /** Virtual key alias or hash the request was billed to. */\n api_key?: string;\n user?: string;\n team_id?: string;\n /**\n * Tags attached to the request (e.g. `channel:backstage`,\n * `session:<thread>`, `invoked-by:<user>`). Shape varies across LiteLLM\n * versions (array or object) and is normalised to a string[].\n */\n request_tags?: string[] | Record<string, string>;\n /** LiteLLM `metadata` blob; carries trace ids and session grouping. */\n metadata?: Record<string, unknown> | string | null;\n}\n\nexport interface SpendLogsParams {\n /** ISO date `YYYY-MM-DD` (inclusive). */\n start_date: string;\n /** ISO date `YYYY-MM-DD` (inclusive). */\n end_date: string;\n /** Restrict to the given virtual key. */\n api_key?: string;\n user_id?: string;\n team_id?: string;\n /** Max rows to return (LiteLLM caps at 1000 per page). */\n page_size?: number;\n}\n\nexport interface AuditLogsParams {\n page?: number;\n page_size?: number;\n start_date?: string;\n end_date?: string;\n action?: string;\n table_name?: string;\n changed_by?: string;\n sort_by?: string;\n sort_order?: 'asc' | 'desc';\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -283,6 +283,42 @@ export interface PaginatedAuditLogs {
|
|
|
283
283
|
page_size: number;
|
|
284
284
|
total_pages: number;
|
|
285
285
|
}
|
|
286
|
+
/** One row from LiteLLM's `/spend/logs` (per-request spend log entry). */
|
|
287
|
+
export interface SpendLogEntry {
|
|
288
|
+
request_id?: string;
|
|
289
|
+
/** ISO timestamp of the call. */
|
|
290
|
+
startTime?: string;
|
|
291
|
+
endTime?: string;
|
|
292
|
+
spend?: number;
|
|
293
|
+
total_tokens?: number;
|
|
294
|
+
prompt_tokens?: number;
|
|
295
|
+
completion_tokens?: number;
|
|
296
|
+
model?: string;
|
|
297
|
+
/** Virtual key alias or hash the request was billed to. */
|
|
298
|
+
api_key?: string;
|
|
299
|
+
user?: string;
|
|
300
|
+
team_id?: string;
|
|
301
|
+
/**
|
|
302
|
+
* Tags attached to the request (e.g. `channel:backstage`,
|
|
303
|
+
* `session:<thread>`, `invoked-by:<user>`). Shape varies across LiteLLM
|
|
304
|
+
* versions (array or object) and is normalised to a string[].
|
|
305
|
+
*/
|
|
306
|
+
request_tags?: string[] | Record<string, string>;
|
|
307
|
+
/** LiteLLM `metadata` blob; carries trace ids and session grouping. */
|
|
308
|
+
metadata?: Record<string, unknown> | string | null;
|
|
309
|
+
}
|
|
310
|
+
export interface SpendLogsParams {
|
|
311
|
+
/** ISO date `YYYY-MM-DD` (inclusive). */
|
|
312
|
+
start_date: string;
|
|
313
|
+
/** ISO date `YYYY-MM-DD` (inclusive). */
|
|
314
|
+
end_date: string;
|
|
315
|
+
/** Restrict to the given virtual key. */
|
|
316
|
+
api_key?: string;
|
|
317
|
+
user_id?: string;
|
|
318
|
+
team_id?: string;
|
|
319
|
+
/** Max rows to return (LiteLLM caps at 1000 per page). */
|
|
320
|
+
page_size?: number;
|
|
321
|
+
}
|
|
286
322
|
export interface AuditLogsParams {
|
|
287
323
|
page?: number;
|
|
288
324
|
page_size?: number;
|