@exulu/backend 1.62.0 → 1.63.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/{catalog-BWE6SLE2.js → catalog-TBSPSN2N.js} +1 -1
- package/dist/{chunk-LYNLQWXC.js → chunk-IZOD2X2F.js} +102 -15
- package/dist/{chunk-ILAHW4UT.js → chunk-YCE44CMU.js} +14 -2
- package/dist/{convert-exulu-tools-to-ai-sdk-tools-2HF7PPYW.js → convert-exulu-tools-to-ai-sdk-tools-THDKPKF3.js} +1 -1
- package/dist/index.cjs +198 -47
- package/dist/index.d.cts +17 -10
- package/dist/index.d.ts +17 -10
- package/dist/index.js +84 -32
- package/ee/rbac-resolver.ts +9 -1
- package/ee/rbac-update.ts +32 -1
- package/ee/schemas.ts +25 -0
- package/ee/workers.ts +1 -1
- package/package.json +1 -1
|
@@ -164,6 +164,7 @@ var checkRecordAccess = async (record, request, user) => {
|
|
|
164
164
|
const isPublic = record.rights_mode === "public";
|
|
165
165
|
const byUsers = record.rights_mode === "users";
|
|
166
166
|
const byRoles = record.rights_mode === "roles";
|
|
167
|
+
const byTeams = record.rights_mode === "teams";
|
|
167
168
|
const createdBy = typeof record.created_by === "string" ? record.created_by : record.created_by?.toString();
|
|
168
169
|
const isCreator = user ? createdBy === user.id.toString() : false;
|
|
169
170
|
const isAdmin = user ? user.super_admin : false;
|
|
@@ -209,6 +210,23 @@ var checkRecordAccess = async (record, request, user) => {
|
|
|
209
210
|
return true;
|
|
210
211
|
}
|
|
211
212
|
}
|
|
213
|
+
if (byTeams) {
|
|
214
|
+
if (!user) {
|
|
215
|
+
setRecordAccessCache(false);
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
hasAccess = record.RBAC?.teams?.find((x) => x.id === user.team?.id)?.rights || "none";
|
|
219
|
+
if (!hasAccess || hasAccess === "none" || hasAccess !== request) {
|
|
220
|
+
console.error(
|
|
221
|
+
`[EXULU] Your current team ${user.team?.name} does not have access to this record, current access type is: ${hasAccess}.`
|
|
222
|
+
);
|
|
223
|
+
setRecordAccessCache(false);
|
|
224
|
+
return false;
|
|
225
|
+
} else {
|
|
226
|
+
setRecordAccessCache(true);
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
212
230
|
setRecordAccessCache(false);
|
|
213
231
|
return false;
|
|
214
232
|
};
|
|
@@ -220,7 +238,8 @@ import { resolve } from "path";
|
|
|
220
238
|
var MAX_CRASHES = 5;
|
|
221
239
|
var INITIAL_BACKOFF_MS = 1e3;
|
|
222
240
|
var MAX_BACKOFF_MS = 3e4;
|
|
223
|
-
var READY_TIMEOUT_MS =
|
|
241
|
+
var READY_TIMEOUT_MS = 9e4;
|
|
242
|
+
var WAIT_TIMEOUT_MS = 6e4;
|
|
224
243
|
var READY_POLL_INTERVAL_MS = 200;
|
|
225
244
|
var SHUTDOWN_GRACE_MS = 5e3;
|
|
226
245
|
var internal = {
|
|
@@ -394,10 +413,18 @@ var startLiteLLMSupervisor = async (options = {}) => {
|
|
|
394
413
|
var waitForLiteLLMReady = async () => {
|
|
395
414
|
if (!isLiteLLMEnabled()) return;
|
|
396
415
|
if (!internal.readyPromise) {
|
|
397
|
-
|
|
398
|
-
return;
|
|
416
|
+
return startLiteLLMSupervisor();
|
|
399
417
|
}
|
|
400
|
-
|
|
418
|
+
const deadline = Date.now() + WAIT_TIMEOUT_MS;
|
|
419
|
+
while (Date.now() < deadline) {
|
|
420
|
+
const s = getSupervisorState();
|
|
421
|
+
if (s === "ready") return;
|
|
422
|
+
if (s === "given_up") {
|
|
423
|
+
throw new Error("LiteLLM supervisor has given up.");
|
|
424
|
+
}
|
|
425
|
+
await new Promise((r) => setTimeout(r, READY_POLL_INTERVAL_MS));
|
|
426
|
+
}
|
|
427
|
+
throw new Error("Timed out waiting for LiteLLM to become ready.");
|
|
401
428
|
};
|
|
402
429
|
var stopLiteLLM = (signal = "SIGTERM") => {
|
|
403
430
|
internal.shutdownRequested = true;
|
|
@@ -424,6 +451,7 @@ var registerShutdownHandlers = () => {
|
|
|
424
451
|
process.on("SIGTERM", () => stopLiteLLM("SIGTERM"));
|
|
425
452
|
process.on("exit", () => stopLiteLLM("SIGTERM"));
|
|
426
453
|
};
|
|
454
|
+
var getSupervisorState = () => internal.state;
|
|
427
455
|
|
|
428
456
|
// src/exulu/tags.ts
|
|
429
457
|
var MAX_LEN = 63;
|
|
@@ -458,6 +486,12 @@ function buildTags(input) {
|
|
|
458
486
|
if (input.agent_name) {
|
|
459
487
|
candidates.push("agent_name_" + input.agent_name);
|
|
460
488
|
}
|
|
489
|
+
if (input.team_id) {
|
|
490
|
+
candidates.push("team_id_" + input.team_id);
|
|
491
|
+
}
|
|
492
|
+
if (input.team_name) {
|
|
493
|
+
candidates.push("team_name_" + input.team_name);
|
|
494
|
+
}
|
|
461
495
|
console.log("[EXULU] Candidates", candidates);
|
|
462
496
|
const out = [];
|
|
463
497
|
for (const candidate of candidates) {
|
|
@@ -561,17 +595,24 @@ var getLiteLLMProvider = ({
|
|
|
561
595
|
user,
|
|
562
596
|
role,
|
|
563
597
|
project,
|
|
564
|
-
agent
|
|
598
|
+
agent,
|
|
599
|
+
team
|
|
565
600
|
}) => {
|
|
566
601
|
if (_litellmProvider) return _litellmProvider;
|
|
567
602
|
const host = process.env.LITELLM_HOST ?? "127.0.0.1";
|
|
568
603
|
const port = process.env.LITELLM_PORT ?? "4000";
|
|
569
604
|
const masterKey = process.env.LITELLM_MASTER_KEY;
|
|
570
605
|
const tags = buildTags({
|
|
571
|
-
user,
|
|
572
|
-
role,
|
|
573
|
-
project,
|
|
574
|
-
agent
|
|
606
|
+
user_id: user?.id,
|
|
607
|
+
role_id: role?.id,
|
|
608
|
+
project_id: project?.id,
|
|
609
|
+
agent_id: agent?.id,
|
|
610
|
+
user_name: !user ? void 0 : user.type === "api" ? user.firstname ?? user.email : user.email,
|
|
611
|
+
role_name: role?.name,
|
|
612
|
+
project_name: project?.name,
|
|
613
|
+
agent_name: agent?.name,
|
|
614
|
+
team_id: team?.id,
|
|
615
|
+
team_name: team?.name
|
|
575
616
|
});
|
|
576
617
|
if (!masterKey) {
|
|
577
618
|
throw new ResolveModelError(
|
|
@@ -610,10 +651,11 @@ async function resolveModel(input) {
|
|
|
610
651
|
);
|
|
611
652
|
}
|
|
612
653
|
const litellm = getLiteLLMProvider({
|
|
613
|
-
user
|
|
614
|
-
role: user?.role
|
|
615
|
-
project
|
|
616
|
-
agent
|
|
654
|
+
user,
|
|
655
|
+
role: user?.role,
|
|
656
|
+
project,
|
|
657
|
+
agent,
|
|
658
|
+
team: user?.team
|
|
617
659
|
});
|
|
618
660
|
const languageModel2 = litellm(modelId);
|
|
619
661
|
const syntheticModel = {
|
|
@@ -755,12 +797,12 @@ var ExuluTool = class {
|
|
|
755
797
|
modelId: agent.model,
|
|
756
798
|
user,
|
|
757
799
|
providers,
|
|
758
|
-
agent
|
|
800
|
+
agent,
|
|
759
801
|
rbacBypass: true
|
|
760
802
|
});
|
|
761
803
|
providerapikey = resolved.apiKey;
|
|
762
804
|
}
|
|
763
|
-
const { convertExuluToolsToAiSdkTools: convertExuluToolsToAiSdkTools2 } = await import("./convert-exulu-tools-to-ai-sdk-tools-
|
|
805
|
+
const { convertExuluToolsToAiSdkTools: convertExuluToolsToAiSdkTools2 } = await import("./convert-exulu-tools-to-ai-sdk-tools-THDKPKF3.js");
|
|
764
806
|
const tools = await convertExuluToolsToAiSdkTools2(
|
|
765
807
|
[this],
|
|
766
808
|
[],
|
|
@@ -1223,6 +1265,12 @@ var authentication = async ({
|
|
|
1223
1265
|
user.role = role;
|
|
1224
1266
|
}
|
|
1225
1267
|
}
|
|
1268
|
+
if (user?.team) {
|
|
1269
|
+
const team = await db2.from("teams").select("*").where("id", user?.team).first();
|
|
1270
|
+
if (team) {
|
|
1271
|
+
user.team = team;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1226
1274
|
if (!user) {
|
|
1227
1275
|
return {
|
|
1228
1276
|
error: true,
|
|
@@ -2324,6 +2372,16 @@ var applyAccessControl = (table, query, user, field_prefix) => {
|
|
|
2324
2372
|
});
|
|
2325
2373
|
});
|
|
2326
2374
|
}
|
|
2375
|
+
if (user?.team) {
|
|
2376
|
+
const userTeamId = user.team.id;
|
|
2377
|
+
this.orWhere(function() {
|
|
2378
|
+
this.where(`${prefix}rights_mode`, "teams").whereExists(function() {
|
|
2379
|
+
this.select("*").from("rbac").whereRaw(
|
|
2380
|
+
"rbac.target_resource_id = " + (prefix ? prefix.slice(0, -1) : tableNamePlural) + ".id"
|
|
2381
|
+
).where("rbac.entity", table.name.singular).where("rbac.access_type", "Team").where("rbac.team_id", userTeamId);
|
|
2382
|
+
});
|
|
2383
|
+
});
|
|
2384
|
+
}
|
|
2327
2385
|
});
|
|
2328
2386
|
} catch (error) {
|
|
2329
2387
|
console.error("Access control error:", error);
|
|
@@ -2536,6 +2594,26 @@ var rolesSchema = {
|
|
|
2536
2594
|
}
|
|
2537
2595
|
]
|
|
2538
2596
|
};
|
|
2597
|
+
var teamsSchema = {
|
|
2598
|
+
type: "teams",
|
|
2599
|
+
name: {
|
|
2600
|
+
plural: "teams",
|
|
2601
|
+
singular: "team"
|
|
2602
|
+
},
|
|
2603
|
+
fields: [
|
|
2604
|
+
{
|
|
2605
|
+
name: "name",
|
|
2606
|
+
type: "text",
|
|
2607
|
+
index: true,
|
|
2608
|
+
unique: true,
|
|
2609
|
+
required: true
|
|
2610
|
+
},
|
|
2611
|
+
{
|
|
2612
|
+
name: "description",
|
|
2613
|
+
type: "text"
|
|
2614
|
+
}
|
|
2615
|
+
]
|
|
2616
|
+
};
|
|
2539
2617
|
var statisticsSchema = {
|
|
2540
2618
|
type: "tracking",
|
|
2541
2619
|
name: {
|
|
@@ -2756,6 +2834,10 @@ var rbacSchema = {
|
|
|
2756
2834
|
name: "role_id",
|
|
2757
2835
|
type: "uuid"
|
|
2758
2836
|
},
|
|
2837
|
+
{
|
|
2838
|
+
name: "team_id",
|
|
2839
|
+
type: "uuid"
|
|
2840
|
+
},
|
|
2759
2841
|
{
|
|
2760
2842
|
name: "user_id",
|
|
2761
2843
|
type: "number"
|
|
@@ -3214,6 +3296,10 @@ var usersSchema = {
|
|
|
3214
3296
|
{
|
|
3215
3297
|
name: "role",
|
|
3216
3298
|
type: "uuid"
|
|
3299
|
+
},
|
|
3300
|
+
{
|
|
3301
|
+
name: "team",
|
|
3302
|
+
type: "uuid"
|
|
3217
3303
|
}
|
|
3218
3304
|
]
|
|
3219
3305
|
};
|
|
@@ -3492,6 +3578,7 @@ var coreSchemas = {
|
|
|
3492
3578
|
}
|
|
3493
3579
|
if (license["rbac"]) {
|
|
3494
3580
|
schemas.rolesSchema = () => addCoreFields(rolesSchema);
|
|
3581
|
+
schemas.teamsSchema = () => addCoreFields(teamsSchema);
|
|
3495
3582
|
schemas.rbacSchema = () => addCoreFields(rbacSchema);
|
|
3496
3583
|
}
|
|
3497
3584
|
if (license["evals"]) {
|
|
@@ -35,6 +35,8 @@ var fetchLiteLLMCatalog = async () => {
|
|
|
35
35
|
region: m.model_info?.region ?? null,
|
|
36
36
|
max_tokens: m.model_info?.max_tokens ?? null,
|
|
37
37
|
max_input_tokens: m.model_info?.max_input_tokens ?? null,
|
|
38
|
+
input_cost_per_million_tokens: m.model_info?.input_cost_per_token * 1e6,
|
|
39
|
+
output_cost_per_million_tokens: m.model_info?.output_cost_per_token * 1e6,
|
|
38
40
|
active: m.model_info?.active ?? true,
|
|
39
41
|
max_output_tokens: m.model_info?.max_output_tokens ?? null,
|
|
40
42
|
supports_vision: !!m.model_info?.supports_vision,
|
|
@@ -46,8 +48,18 @@ var fetchLiteLLMCatalog = async () => {
|
|
|
46
48
|
supports_edit: !!m.model_info?.supports_edit,
|
|
47
49
|
max_n: typeof m.model_info?.max_n === "number" ? m.model_info.max_n : null
|
|
48
50
|
}));
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
const map = /* @__PURE__ */ new Map();
|
|
52
|
+
for (const item of items) {
|
|
53
|
+
const key = `${item.model_name}-${item.upstream_model}`;
|
|
54
|
+
if (map.has(key)) {
|
|
55
|
+
map.get(key).tags.push(...item.tags);
|
|
56
|
+
} else {
|
|
57
|
+
map.set(key, item);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const uniqueItems = Array.from(map.values());
|
|
61
|
+
_cache = { expiresAt: Date.now() + CACHE_TTL_MS, items: uniqueItems };
|
|
62
|
+
return uniqueItems.filter((m) => m.type !== "speech_to_text" && m.type !== "text_to_speech");
|
|
51
63
|
} catch (err) {
|
|
52
64
|
console.error("[EXULU] litellmCatalog: failed to fetch /model/info:", err);
|
|
53
65
|
return [];
|