@exulu/backend 1.62.1 → 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.
@@ -2,7 +2,7 @@ import {
2
2
  __resetLiteLLMCatalogCacheForTesting,
3
3
  fetchLiteLLMCatalog,
4
4
  findLiteLLMModel
5
- } from "./chunk-ILAHW4UT.js";
5
+ } from "./chunk-YCE44CMU.js";
6
6
  export {
7
7
  __resetLiteLLMCatalogCacheForTesting,
8
8
  fetchLiteLLMCatalog,
@@ -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
  };
@@ -468,6 +486,12 @@ function buildTags(input) {
468
486
  if (input.agent_name) {
469
487
  candidates.push("agent_name_" + input.agent_name);
470
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
+ }
471
495
  console.log("[EXULU] Candidates", candidates);
472
496
  const out = [];
473
497
  for (const candidate of candidates) {
@@ -571,17 +595,24 @@ var getLiteLLMProvider = ({
571
595
  user,
572
596
  role,
573
597
  project,
574
- agent
598
+ agent,
599
+ team
575
600
  }) => {
576
601
  if (_litellmProvider) return _litellmProvider;
577
602
  const host = process.env.LITELLM_HOST ?? "127.0.0.1";
578
603
  const port = process.env.LITELLM_PORT ?? "4000";
579
604
  const masterKey = process.env.LITELLM_MASTER_KEY;
580
605
  const tags = buildTags({
581
- user,
582
- role,
583
- project,
584
- 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
585
616
  });
586
617
  if (!masterKey) {
587
618
  throw new ResolveModelError(
@@ -620,10 +651,11 @@ async function resolveModel(input) {
620
651
  );
621
652
  }
622
653
  const litellm = getLiteLLMProvider({
623
- user: user?.id,
624
- role: user?.role?.id,
625
- project: project?.id,
626
- agent: agent?.id
654
+ user,
655
+ role: user?.role,
656
+ project,
657
+ agent,
658
+ team: user?.team
627
659
  });
628
660
  const languageModel2 = litellm(modelId);
629
661
  const syntheticModel = {
@@ -765,12 +797,12 @@ var ExuluTool = class {
765
797
  modelId: agent.model,
766
798
  user,
767
799
  providers,
768
- agent: { id: agent.id },
800
+ agent,
769
801
  rbacBypass: true
770
802
  });
771
803
  providerapikey = resolved.apiKey;
772
804
  }
773
- const { convertExuluToolsToAiSdkTools: convertExuluToolsToAiSdkTools2 } = await import("./convert-exulu-tools-to-ai-sdk-tools-FZ4ZCVBZ.js");
805
+ const { convertExuluToolsToAiSdkTools: convertExuluToolsToAiSdkTools2 } = await import("./convert-exulu-tools-to-ai-sdk-tools-THDKPKF3.js");
774
806
  const tools = await convertExuluToolsToAiSdkTools2(
775
807
  [this],
776
808
  [],
@@ -1233,6 +1265,12 @@ var authentication = async ({
1233
1265
  user.role = role;
1234
1266
  }
1235
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
+ }
1236
1274
  if (!user) {
1237
1275
  return {
1238
1276
  error: true,
@@ -2334,6 +2372,16 @@ var applyAccessControl = (table, query, user, field_prefix) => {
2334
2372
  });
2335
2373
  });
2336
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
+ }
2337
2385
  });
2338
2386
  } catch (error) {
2339
2387
  console.error("Access control error:", error);
@@ -2546,6 +2594,26 @@ var rolesSchema = {
2546
2594
  }
2547
2595
  ]
2548
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
+ };
2549
2617
  var statisticsSchema = {
2550
2618
  type: "tracking",
2551
2619
  name: {
@@ -2766,6 +2834,10 @@ var rbacSchema = {
2766
2834
  name: "role_id",
2767
2835
  type: "uuid"
2768
2836
  },
2837
+ {
2838
+ name: "team_id",
2839
+ type: "uuid"
2840
+ },
2769
2841
  {
2770
2842
  name: "user_id",
2771
2843
  type: "number"
@@ -3224,6 +3296,10 @@ var usersSchema = {
3224
3296
  {
3225
3297
  name: "role",
3226
3298
  type: "uuid"
3299
+ },
3300
+ {
3301
+ name: "team",
3302
+ type: "uuid"
3227
3303
  }
3228
3304
  ]
3229
3305
  };
@@ -3502,6 +3578,7 @@ var coreSchemas = {
3502
3578
  }
3503
3579
  if (license["rbac"]) {
3504
3580
  schemas.rolesSchema = () => addCoreFields(rolesSchema);
3581
+ schemas.teamsSchema = () => addCoreFields(teamsSchema);
3505
3582
  schemas.rbacSchema = () => addCoreFields(rbacSchema);
3506
3583
  }
3507
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
- _cache = { expiresAt: Date.now() + CACHE_TTL_MS, items };
50
- return items.filter((m) => m.type !== "speech_to_text" && m.type !== "text_to_speech");
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 [];
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  convertExuluToolsToAiSdkTools
3
- } from "./chunk-4TCN467I.js";
3
+ } from "./chunk-IZOD2X2F.js";
4
4
  export {
5
5
  convertExuluToolsToAiSdkTools
6
6
  };
package/dist/index.cjs CHANGED
@@ -267,6 +267,12 @@ var init_auth = __esm({
267
267
  user.role = role;
268
268
  }
269
269
  }
270
+ if (user?.team) {
271
+ const team = await db2.from("teams").select("*").where("id", user?.team).first();
272
+ if (team) {
273
+ user.team = team;
274
+ }
275
+ }
270
276
  if (!user) {
271
277
  return {
272
278
  error: true,
@@ -637,6 +643,7 @@ var init_check_record_access = __esm({
637
643
  const isPublic = record.rights_mode === "public";
638
644
  const byUsers = record.rights_mode === "users";
639
645
  const byRoles = record.rights_mode === "roles";
646
+ const byTeams = record.rights_mode === "teams";
640
647
  const createdBy = typeof record.created_by === "string" ? record.created_by : record.created_by?.toString();
641
648
  const isCreator = user ? createdBy === user.id.toString() : false;
642
649
  const isAdmin = user ? user.super_admin : false;
@@ -682,6 +689,23 @@ var init_check_record_access = __esm({
682
689
  return true;
683
690
  }
684
691
  }
692
+ if (byTeams) {
693
+ if (!user) {
694
+ setRecordAccessCache(false);
695
+ return false;
696
+ }
697
+ hasAccess = record.RBAC?.teams?.find((x) => x.id === user.team?.id)?.rights || "none";
698
+ if (!hasAccess || hasAccess === "none" || hasAccess !== request2) {
699
+ console.error(
700
+ `[EXULU] Your current team ${user.team?.name} does not have access to this record, current access type is: ${hasAccess}.`
701
+ );
702
+ setRecordAccessCache(false);
703
+ return false;
704
+ } else {
705
+ setRecordAccessCache(true);
706
+ return true;
707
+ }
708
+ }
685
709
  setRecordAccessCache(false);
686
710
  return false;
687
711
  };
@@ -784,6 +808,12 @@ function buildTags(input) {
784
808
  if (input.agent_name) {
785
809
  candidates.push("agent_name_" + input.agent_name);
786
810
  }
811
+ if (input.team_id) {
812
+ candidates.push("team_id_" + input.team_id);
813
+ }
814
+ if (input.team_name) {
815
+ candidates.push("team_name_" + input.team_name);
816
+ }
787
817
  console.log("[EXULU] Candidates", candidates);
788
818
  const out = [];
789
819
  for (const candidate of candidates) {
@@ -881,10 +911,11 @@ async function resolveModel(input) {
881
911
  );
882
912
  }
883
913
  const litellm = getLiteLLMProvider({
884
- user: user?.id,
885
- role: user?.role?.id,
886
- project: project?.id,
887
- agent: agent?.id
914
+ user,
915
+ role: user?.role,
916
+ project,
917
+ agent,
918
+ team: user?.team
888
919
  });
889
920
  const languageModel2 = litellm(modelId);
890
921
  const syntheticModel = {
@@ -996,17 +1027,24 @@ var init_resolve_model = __esm({
996
1027
  user,
997
1028
  role,
998
1029
  project,
999
- agent
1030
+ agent,
1031
+ team
1000
1032
  }) => {
1001
1033
  if (_litellmProvider) return _litellmProvider;
1002
1034
  const host = process.env.LITELLM_HOST ?? "127.0.0.1";
1003
1035
  const port = process.env.LITELLM_PORT ?? "4000";
1004
1036
  const masterKey = process.env.LITELLM_MASTER_KEY;
1005
1037
  const tags = buildTags({
1006
- user,
1007
- role,
1008
- project,
1009
- agent
1038
+ user_id: user?.id,
1039
+ role_id: role?.id,
1040
+ project_id: project?.id,
1041
+ agent_id: agent?.id,
1042
+ user_name: !user ? void 0 : user.type === "api" ? user.firstname ?? user.email : user.email,
1043
+ role_name: role?.name,
1044
+ project_name: project?.name,
1045
+ agent_name: agent?.name,
1046
+ team_id: team?.id,
1047
+ team_name: team?.name
1010
1048
  });
1011
1049
  if (!masterKey) {
1012
1050
  throw new ResolveModelError(
@@ -3328,7 +3366,7 @@ var init_tool = __esm({
3328
3366
  modelId: agent.model,
3329
3367
  user,
3330
3368
  providers,
3331
- agent: { id: agent.id },
3369
+ agent,
3332
3370
  rbacBypass: true
3333
3371
  });
3334
3372
  providerapikey = resolved.apiKey;
@@ -3698,6 +3736,16 @@ var init_access_control = __esm({
3698
3736
  });
3699
3737
  });
3700
3738
  }
3739
+ if (user?.team) {
3740
+ const userTeamId = user.team.id;
3741
+ this.orWhere(function() {
3742
+ this.where(`${prefix}rights_mode`, "teams").whereExists(function() {
3743
+ this.select("*").from("rbac").whereRaw(
3744
+ "rbac.target_resource_id = " + (prefix ? prefix.slice(0, -1) : tableNamePlural) + ".id"
3745
+ ).where("rbac.entity", table.name.singular).where("rbac.access_type", "Team").where("rbac.team_id", userTeamId);
3746
+ });
3747
+ });
3748
+ }
3701
3749
  });
3702
3750
  } catch (error) {
3703
3751
  console.error("Access control error:", error);
@@ -3840,7 +3888,7 @@ var init_vector_methods = __esm({
3840
3888
  });
3841
3889
 
3842
3890
  // ee/schemas.ts
3843
- var feedbackSchema, rolesSchema, statisticsSchema, testCasesSchema, evalSetsSchema, jobResultsSchema, evalRunsSchema, rbacSchema, workflowTemplatesSchema;
3891
+ var feedbackSchema, rolesSchema, teamsSchema, statisticsSchema, testCasesSchema, evalSetsSchema, jobResultsSchema, evalRunsSchema, rbacSchema, workflowTemplatesSchema;
3844
3892
  var init_schemas = __esm({
3845
3893
  "ee/schemas.ts"() {
3846
3894
  "use strict";
@@ -3924,6 +3972,26 @@ var init_schemas = __esm({
3924
3972
  }
3925
3973
  ]
3926
3974
  };
3975
+ teamsSchema = {
3976
+ type: "teams",
3977
+ name: {
3978
+ plural: "teams",
3979
+ singular: "team"
3980
+ },
3981
+ fields: [
3982
+ {
3983
+ name: "name",
3984
+ type: "text",
3985
+ index: true,
3986
+ unique: true,
3987
+ required: true
3988
+ },
3989
+ {
3990
+ name: "description",
3991
+ type: "text"
3992
+ }
3993
+ ]
3994
+ };
3927
3995
  statisticsSchema = {
3928
3996
  type: "tracking",
3929
3997
  name: {
@@ -4144,6 +4212,10 @@ var init_schemas = __esm({
4144
4212
  name: "role_id",
4145
4213
  type: "uuid"
4146
4214
  },
4215
+ {
4216
+ name: "team_id",
4217
+ type: "uuid"
4218
+ },
4147
4219
  {
4148
4220
  name: "user_id",
4149
4221
  type: "number"
@@ -4611,6 +4683,10 @@ var init_core_schema = __esm({
4611
4683
  {
4612
4684
  name: "role",
4613
4685
  type: "uuid"
4686
+ },
4687
+ {
4688
+ name: "team",
4689
+ type: "uuid"
4614
4690
  }
4615
4691
  ]
4616
4692
  };
@@ -4889,6 +4965,7 @@ var init_core_schema = __esm({
4889
4965
  }
4890
4966
  if (license["rbac"]) {
4891
4967
  schemas.rolesSchema = () => addCoreFields(rolesSchema);
4968
+ schemas.teamsSchema = () => addCoreFields(teamsSchema);
4892
4969
  schemas.rbacSchema = () => addCoreFields(rbacSchema);
4893
4970
  }
4894
4971
  if (license["evals"]) {
@@ -7779,6 +7856,8 @@ var init_catalog = __esm({
7779
7856
  region: m.model_info?.region ?? null,
7780
7857
  max_tokens: m.model_info?.max_tokens ?? null,
7781
7858
  max_input_tokens: m.model_info?.max_input_tokens ?? null,
7859
+ input_cost_per_million_tokens: m.model_info?.input_cost_per_token * 1e6,
7860
+ output_cost_per_million_tokens: m.model_info?.output_cost_per_token * 1e6,
7782
7861
  active: m.model_info?.active ?? true,
7783
7862
  max_output_tokens: m.model_info?.max_output_tokens ?? null,
7784
7863
  supports_vision: !!m.model_info?.supports_vision,
@@ -7790,8 +7869,18 @@ var init_catalog = __esm({
7790
7869
  supports_edit: !!m.model_info?.supports_edit,
7791
7870
  max_n: typeof m.model_info?.max_n === "number" ? m.model_info.max_n : null
7792
7871
  }));
7793
- _cache = { expiresAt: Date.now() + CACHE_TTL_MS2, items };
7794
- return items.filter((m) => m.type !== "speech_to_text" && m.type !== "text_to_speech");
7872
+ const map = /* @__PURE__ */ new Map();
7873
+ for (const item of items) {
7874
+ const key2 = `${item.model_name}-${item.upstream_model}`;
7875
+ if (map.has(key2)) {
7876
+ map.get(key2).tags.push(...item.tags);
7877
+ } else {
7878
+ map.set(key2, item);
7879
+ }
7880
+ }
7881
+ const uniqueItems = Array.from(map.values());
7882
+ _cache = { expiresAt: Date.now() + CACHE_TTL_MS2, items: uniqueItems };
7883
+ return uniqueItems.filter((m) => m.type !== "speech_to_text" && m.type !== "text_to_speech");
7795
7884
  } catch (err) {
7796
7885
  console.error("[EXULU] litellmCatalog: failed to fetch /model/info:", err);
7797
7886
  return [];
@@ -8313,7 +8402,8 @@ var RBACResolver = async (db2, entityName, resourceId, rights_mode) => {
8313
8402
  return {
8314
8403
  type: "public",
8315
8404
  users: [],
8316
- roles: []
8405
+ roles: [],
8406
+ teams: []
8317
8407
  };
8318
8408
  }
8319
8409
  const rbacRecords = await db2.from("rbac").where({
@@ -8322,13 +8412,16 @@ var RBACResolver = async (db2, entityName, resourceId, rights_mode) => {
8322
8412
  }).select("*");
8323
8413
  const users = rbacRecords.filter((r) => r.access_type === "User")?.map((r) => ({ id: r.user_id, rights: r.rights }));
8324
8414
  const roles = rbacRecords.filter((r) => r.access_type === "Role")?.map((r) => ({ id: r.role_id, rights: r.rights }));
8415
+ const teams = rbacRecords.filter((r) => r.access_type === "Team")?.map((r) => ({ id: r.team_id, rights: r.rights }));
8325
8416
  let type = rights_mode || "private";
8326
8417
  if (type === "users" && users.length === 0) type = "private";
8327
8418
  if (type === "roles" && roles.length === 0) type = "private";
8419
+ if (type === "teams" && teams.length === 0) type = "private";
8328
8420
  return {
8329
8421
  type,
8330
8422
  users,
8331
- roles
8423
+ roles,
8424
+ teams
8332
8425
  };
8333
8426
  };
8334
8427
 
@@ -9085,7 +9178,8 @@ var handleRBACUpdate = async (db2, entityName, resourceId, rbacData, existingRba
9085
9178
  }
9086
9179
  const {
9087
9180
  users = [],
9088
- roles = []
9181
+ roles = [],
9182
+ teams = []
9089
9183
  /* projects = [] */
9090
9184
  } = rbacData;
9091
9185
  if (!existingRbacRecords) {
@@ -9096,20 +9190,28 @@ var handleRBACUpdate = async (db2, entityName, resourceId, rbacData, existingRba
9096
9190
  }
9097
9191
  const newUserRecords = new Set(users.map((u) => `${u.id}:${u.rights}`));
9098
9192
  const newRoleRecords = new Set(roles.map((r) => `${r.id}:${r.rights}`));
9193
+ const newTeamRecords = new Set(teams.map((t) => `${t.id}:${t.rights}`));
9099
9194
  const existingUserRecords = new Set(
9100
9195
  existingRbacRecords.filter((r) => r.access_type === "User").map((r) => `${r.user_id}:${r.rights}`)
9101
9196
  );
9102
9197
  const existingRoleRecords = new Set(
9103
9198
  existingRbacRecords.filter((r) => r.access_type === "Role").map((r) => `${r.role_id}:${r.rights}`)
9104
9199
  );
9200
+ const existingTeamRecords = new Set(
9201
+ existingRbacRecords.filter((r) => r.access_type === "Team").map((r) => `${r.team_id}:${r.rights}`)
9202
+ );
9105
9203
  const usersToCreate = users.filter((u) => !existingUserRecords.has(`${u.id}:${u.rights}`));
9106
9204
  const rolesToCreate = roles.filter((r) => !existingRoleRecords.has(`${r.id}:${r.rights}`));
9205
+ const teamsToCreate = teams.filter((t) => !existingTeamRecords.has(`${t.id}:${t.rights}`));
9107
9206
  const usersToRemove = existingRbacRecords.filter(
9108
9207
  (r) => r.access_type === "User" && !newUserRecords.has(`${r.user_id}:${r.rights}`)
9109
9208
  );
9110
9209
  const rolesToRemove = existingRbacRecords.filter(
9111
9210
  (r) => r.access_type === "Role" && !newRoleRecords.has(`${r.role_id}:${r.rights}`)
9112
9211
  );
9212
+ const teamsToRemove = existingRbacRecords.filter(
9213
+ (r) => r.access_type === "Team" && !newTeamRecords.has(`${r.team_id}:${r.rights}`)
9214
+ );
9113
9215
  if (usersToRemove.length > 0) {
9114
9216
  await db2.from("rbac").whereIn(
9115
9217
  "id",
@@ -9122,6 +9224,12 @@ var handleRBACUpdate = async (db2, entityName, resourceId, rbacData, existingRba
9122
9224
  rolesToRemove.map((r) => r.id)
9123
9225
  ).del();
9124
9226
  }
9227
+ if (teamsToRemove.length > 0) {
9228
+ await db2.from("rbac").whereIn(
9229
+ "id",
9230
+ teamsToRemove.map((r) => r.id)
9231
+ ).del();
9232
+ }
9125
9233
  const recordsToInsert = [];
9126
9234
  usersToCreate.forEach((user) => {
9127
9235
  recordsToInsert.push({
@@ -9145,6 +9253,17 @@ var handleRBACUpdate = async (db2, entityName, resourceId, rbacData, existingRba
9145
9253
  updatedAt: /* @__PURE__ */ new Date()
9146
9254
  });
9147
9255
  });
9256
+ teamsToCreate.forEach((team) => {
9257
+ recordsToInsert.push({
9258
+ entity: entityName,
9259
+ access_type: "Team",
9260
+ target_resource_id: resourceId,
9261
+ team_id: team.id,
9262
+ rights: team.rights,
9263
+ createdAt: /* @__PURE__ */ new Date(),
9264
+ updatedAt: /* @__PURE__ */ new Date()
9265
+ });
9266
+ });
9148
9267
  if (recordsToInsert.length > 0) {
9149
9268
  await db2.from("rbac").insert(recordsToInsert);
9150
9269
  }
@@ -9343,6 +9462,19 @@ function createMutations(table, providers, contexts, rerankers, tools, config) {
9343
9462
  }
9344
9463
  throw new Error("Insufficient role permissions to edit this record");
9345
9464
  }
9465
+ if (record.rights_mode === "teams" && user.team) {
9466
+ const rbacRecord = await db2.from("rbac").where({
9467
+ entity: table.name.singular,
9468
+ target_resource_id: id,
9469
+ access_type: "Team",
9470
+ team_id: user.team,
9471
+ rights: "write"
9472
+ }).first();
9473
+ if (rbacRecord) {
9474
+ return true;
9475
+ }
9476
+ throw new Error("Insufficient team permissions to edit this record");
9477
+ }
9346
9478
  throw new Error("Insufficient permissions to edit this record");
9347
9479
  } catch (error) {
9348
9480
  console.error("Write access validation error:", error);
@@ -11046,7 +11178,7 @@ var processUiMessagesFlow = async ({
11046
11178
  modelId: agent.model,
11047
11179
  user,
11048
11180
  providers,
11049
- agent: { id: agent.id }
11181
+ agent
11050
11182
  });
11051
11183
  const providerapikey = resolved.apiKey;
11052
11184
  const resolvedLanguageModel = resolved.languageModel;
@@ -12087,6 +12219,8 @@ type LiteLLMModel {
12087
12219
  supports_function_calling: Boolean
12088
12220
  supports_pdf_input: Boolean
12089
12221
  supports_audio_input: Boolean
12222
+ input_cost_per_million_tokens: Float
12223
+ output_cost_per_million_tokens: Float
12090
12224
  }
12091
12225
  `;
12092
12226
  resolvers.Query["agentRateLimitUsage"] = async (_, args, context) => {
@@ -13678,7 +13812,7 @@ var ExuluProvider = class {
13678
13812
  modelId: agent.model,
13679
13813
  user,
13680
13814
  providers,
13681
- agent: { id: agent.id }
13815
+ agent
13682
13816
  });
13683
13817
  const providerapikey = resolved.apiKey;
13684
13818
  console.log(
@@ -15386,7 +15520,7 @@ var registerOpenAIGatewayRoutes = async (app, providers, tools, contexts, config
15386
15520
  });
15387
15521
  return;
15388
15522
  }
15389
- let project = null;
15523
+ let project = void 0;
15390
15524
  if (projectName) {
15391
15525
  let projectQuery = db2("projects").select("*");
15392
15526
  projectQuery = applyAccessControl(projectsSchema4(), projectQuery, user);
@@ -15409,8 +15543,8 @@ var registerOpenAIGatewayRoutes = async (app, providers, tools, contexts, config
15409
15543
  modelId: agent.model,
15410
15544
  user,
15411
15545
  providers,
15412
- agent: { id: agent.id },
15413
- project: project ? { id: project.id } : void 0
15546
+ agent,
15547
+ project
15414
15548
  });
15415
15549
  } catch (err) {
15416
15550
  if (err instanceof ResolveModelError) {
@@ -15587,6 +15721,7 @@ var {
15587
15721
  rbacSchema: rbacSchema2,
15588
15722
  promptLibrarySchema: promptLibrarySchema2,
15589
15723
  contextPresetsSchema: contextPresetsSchema2,
15724
+ teamsSchema: teamsSchema2,
15590
15725
  embedderSettingsSchema: embedderSettingsSchema2,
15591
15726
  promptFavoritesSchema: promptFavoritesSchema2,
15592
15727
  statisticsSchema: statisticsSchema2,
@@ -15636,6 +15771,7 @@ var createExpressRoutes = async (app, providers, tools, contexts, config, evals,
15636
15771
  jobResultsSchema2(),
15637
15772
  promptLibrarySchema2(),
15638
15773
  contextPresetsSchema2(),
15774
+ teamsSchema2(),
15639
15775
  embedderSettingsSchema2(),
15640
15776
  promptFavoritesSchema2(),
15641
15777
  evalRunsSchema2(),
@@ -16022,7 +16158,7 @@ Mood: friendly and intelligent.
16022
16158
  modelId,
16023
16159
  user,
16024
16160
  providers,
16025
- agent: { id: agent.id }
16161
+ agent
16026
16162
  });
16027
16163
  } catch (err) {
16028
16164
  if (err instanceof ResolveModelError) {
@@ -16283,7 +16419,7 @@ ${customInstructions}` : agent.instructions;
16283
16419
  modelId: agent.model,
16284
16420
  user,
16285
16421
  providers,
16286
- agent: { id: agent.id }
16422
+ agent
16287
16423
  });
16288
16424
  } catch (err) {
16289
16425
  if (err instanceof ResolveModelError) {
@@ -17095,7 +17231,9 @@ ${style.markdown}` : params.prompt;
17095
17231
  project_id: project?.id,
17096
17232
  user_name: user.email,
17097
17233
  role_name: user.role?.name,
17098
- project_name: project?.name
17234
+ project_name: project?.name,
17235
+ team_id: user.team?.id,
17236
+ team_name: user.team?.name
17099
17237
  });
17100
17238
  if (tags?.length) {
17101
17239
  upstreamHeaders["x-litellm-tags"] = tags.join(",");
@@ -18140,7 +18278,7 @@ var ExuluMCP = class {
18140
18278
  modelId: agent.model,
18141
18279
  user,
18142
18280
  providers: allProviders,
18143
- agent: { id: agent.id }
18281
+ agent
18144
18282
  });
18145
18283
  const providerapikey = resolved.apiKey;
18146
18284
  if (!isLiteLLMEnabled()) {
@@ -19386,6 +19524,7 @@ var ExuluEval = class {
19386
19524
  init_resolve_model();
19387
19525
  init_singleton();
19388
19526
  var import_zod14 = require("zod");
19527
+ var import_ai14 = require("ai");
19389
19528
  var llmAsJudgeEval = () => {
19390
19529
  if (process.env.REDIS_HOST?.length && process.env.REDIS_PORT?.length) {
19391
19530
  return new ExuluEval({
@@ -19426,27 +19565,27 @@ var llmAsJudgeEval = () => {
19426
19565
  const resolved = await resolveModel({
19427
19566
  modelId: agent.model,
19428
19567
  providers: exuluApp.get().providers,
19429
- agent: { id: agent.id },
19568
+ agent,
19430
19569
  rbacBypass: true
19431
19570
  });
19432
- const providerapikey = resolved.apiKey;
19433
19571
  console.log("[EXULU] prompt", prompt);
19434
- const response = await provider.generateSync({
19435
- agent,
19436
- contexts: [],
19437
- rerankers: [],
19572
+ const { output } = await (0, import_ai14.generateText)({
19573
+ temperature: 0,
19574
+ model: resolved.languageModel,
19575
+ system: "",
19438
19576
  prompt,
19439
- outputSchema: import_zod14.z.object({
19440
- score: import_zod14.z.number().min(0).max(100).describe("The score between 0 and 100.")
19441
- }),
19442
- languageModel: resolved.languageModel,
19443
- providerapikey
19577
+ maxRetries: 2,
19578
+ output: import_ai14.Output.object({
19579
+ schema: import_zod14.z.object({
19580
+ score: import_zod14.z.number().min(0).max(100).describe("The score between 0 and 100.")
19581
+ })
19582
+ })
19444
19583
  });
19445
- console.log("[EXULU] response", response);
19446
- const score = parseFloat(response.score);
19584
+ console.log("[EXULU] output", output);
19585
+ const score = output.score;
19447
19586
  if (isNaN(score)) {
19448
19587
  throw new Error(
19449
- `Generated score from llm as a judge eval is not a number: ${response.score}`
19588
+ `Generated score from llm as a judge eval is not a number: ${output.score}`
19450
19589
  );
19451
19590
  }
19452
19591
  return score;
@@ -22853,6 +22992,7 @@ var {
22853
22992
  agentMessagesSchema: agentMessagesSchema3,
22854
22993
  modelsSchema: modelsSchema3,
22855
22994
  rolesSchema: rolesSchema3,
22995
+ teamsSchema: teamsSchema3,
22856
22996
  usersSchema: usersSchema3,
22857
22997
  skillsSchema: skillsSchema3,
22858
22998
  statisticsSchema: statisticsSchema3,
@@ -22895,6 +23035,7 @@ var up = async function(knex) {
22895
23035
  agentMessagesSchema3(),
22896
23036
  modelsSchema3(),
22897
23037
  rolesSchema3(),
23038
+ teamsSchema3(),
22898
23039
  testCasesSchema3(),
22899
23040
  evalSetsSchema3(),
22900
23041
  evalRunsSchema3(),
@@ -23922,7 +24063,7 @@ var MarkdownChunker = class {
23922
24063
  init_cjs_shims();
23923
24064
  var fs5 = __toESM(require("fs"), 1);
23924
24065
  var path2 = __toESM(require("path"), 1);
23925
- var import_ai14 = require("ai");
24066
+ var import_ai15 = require("ai");
23926
24067
  var import_zod22 = require("zod");
23927
24068
  var import_p_limit = __toESM(require("p-limit"), 1);
23928
24069
  var import_crypto = require("crypto");
@@ -24275,9 +24416,9 @@ If the page contains a flow-chart, schematic, technical drawing or control board
24275
24416
 
24276
24417
  ### 7. Only populate \`corrected_text\` when \`needs_correction\` is true. If the OCR output is accurate, return \`needs_correction: false\` and \`corrected_content: null\`.
24277
24418
  `;
24278
- const result = await (0, import_ai14.generateText)({
24419
+ const result = await (0, import_ai15.generateText)({
24279
24420
  model,
24280
- output: import_ai14.Output.object({
24421
+ output: import_ai15.Output.object({
24281
24422
  schema: import_zod22.z.object({
24282
24423
  needs_correction: import_zod22.z.boolean(),
24283
24424
  corrected_text: import_zod22.z.string().nullable(),
package/dist/index.d.cts CHANGED
@@ -24,15 +24,22 @@ type User = {
24
24
  favourite_agents?: string[];
25
25
  scope_mode?: ApiKeyScopeMode;
26
26
  agent_ids?: string[];
27
- role: {
28
- id: string;
29
- name: string;
30
- agents: "read" | "write";
31
- evals: "read" | "write";
32
- workflows: "read" | "write";
33
- variables: "read" | "write";
34
- users: "read" | "write";
35
- };
27
+ role: UserRole;
28
+ team?: ExuluTeam;
29
+ };
30
+ type UserRole = {
31
+ id: string;
32
+ name: string;
33
+ agents: "read" | "write";
34
+ evals: "read" | "write";
35
+ workflows: "read" | "write";
36
+ variables: "read" | "write";
37
+ users: "read" | "write";
38
+ };
39
+ type ExuluTeam = {
40
+ id: string;
41
+ name: string;
42
+ description?: string;
36
43
  };
37
44
 
38
45
  declare function redisClient(): Promise<{
@@ -789,7 +796,7 @@ declare class ExuluProvider {
789
796
  get providerName(): string;
790
797
  get modelName(): string;
791
798
  tool: (instance: string, providers: ExuluProvider[], contexts: ExuluContext[], rerankers: ExuluReranker[]) => Promise<ExuluTool | null>;
792
- generateSync: ({ prompt, req, user, session, inputMessages, approvedTools, currentTools, currentSkills, allExuluTools, statistics, toolConfigs, providerapikey, languageModel, contexts, rerankers, exuluConfig, agent, instructions, maxStepCount, onTokenUsage, }: {
799
+ generateSync: ({ prompt, req, user, session, inputMessages, approvedTools, currentTools, currentSkills, allExuluTools, statistics, toolConfigs, providerapikey, languageModel, contexts, rerankers, exuluConfig, agent, instructions, maxStepCount, onTokenUsage }: {
793
800
  prompt?: string;
794
801
  user?: User;
795
802
  maxStepCount?: number;
package/dist/index.d.ts CHANGED
@@ -24,15 +24,22 @@ type User = {
24
24
  favourite_agents?: string[];
25
25
  scope_mode?: ApiKeyScopeMode;
26
26
  agent_ids?: string[];
27
- role: {
28
- id: string;
29
- name: string;
30
- agents: "read" | "write";
31
- evals: "read" | "write";
32
- workflows: "read" | "write";
33
- variables: "read" | "write";
34
- users: "read" | "write";
35
- };
27
+ role: UserRole;
28
+ team?: ExuluTeam;
29
+ };
30
+ type UserRole = {
31
+ id: string;
32
+ name: string;
33
+ agents: "read" | "write";
34
+ evals: "read" | "write";
35
+ workflows: "read" | "write";
36
+ variables: "read" | "write";
37
+ users: "read" | "write";
38
+ };
39
+ type ExuluTeam = {
40
+ id: string;
41
+ name: string;
42
+ description?: string;
36
43
  };
37
44
 
38
45
  declare function redisClient(): Promise<{
@@ -789,7 +796,7 @@ declare class ExuluProvider {
789
796
  get providerName(): string;
790
797
  get modelName(): string;
791
798
  tool: (instance: string, providers: ExuluProvider[], contexts: ExuluContext[], rerankers: ExuluReranker[]) => Promise<ExuluTool | null>;
792
- generateSync: ({ prompt, req, user, session, inputMessages, approvedTools, currentTools, currentSkills, allExuluTools, statistics, toolConfigs, providerapikey, languageModel, contexts, rerankers, exuluConfig, agent, instructions, maxStepCount, onTokenUsage, }: {
799
+ generateSync: ({ prompt, req, user, session, inputMessages, approvedTools, currentTools, currentSkills, allExuluTools, statistics, toolConfigs, providerapikey, languageModel, contexts, rerankers, exuluConfig, agent, instructions, maxStepCount, onTokenUsage }: {
793
800
  prompt?: string;
794
801
  user?: User;
795
802
  maxStepCount?: number;
package/dist/index.js CHANGED
@@ -53,10 +53,10 @@ import {
53
53
  vectorSearch,
54
54
  waitForLiteLLMReady,
55
55
  withRetry
56
- } from "./chunk-4TCN467I.js";
56
+ } from "./chunk-IZOD2X2F.js";
57
57
  import {
58
58
  findLiteLLMModel
59
- } from "./chunk-ILAHW4UT.js";
59
+ } from "./chunk-YCE44CMU.js";
60
60
 
61
61
  // src/index.ts
62
62
  import "dotenv/config";
@@ -504,7 +504,8 @@ var RBACResolver = async (db, entityName, resourceId, rights_mode) => {
504
504
  return {
505
505
  type: "public",
506
506
  users: [],
507
- roles: []
507
+ roles: [],
508
+ teams: []
508
509
  };
509
510
  }
510
511
  const rbacRecords = await db.from("rbac").where({
@@ -513,13 +514,16 @@ var RBACResolver = async (db, entityName, resourceId, rights_mode) => {
513
514
  }).select("*");
514
515
  const users = rbacRecords.filter((r) => r.access_type === "User")?.map((r) => ({ id: r.user_id, rights: r.rights }));
515
516
  const roles = rbacRecords.filter((r) => r.access_type === "Role")?.map((r) => ({ id: r.role_id, rights: r.rights }));
517
+ const teams = rbacRecords.filter((r) => r.access_type === "Team")?.map((r) => ({ id: r.team_id, rights: r.rights }));
516
518
  let type = rights_mode || "private";
517
519
  if (type === "users" && users.length === 0) type = "private";
518
520
  if (type === "roles" && roles.length === 0) type = "private";
521
+ if (type === "teams" && teams.length === 0) type = "private";
519
522
  return {
520
523
  type,
521
524
  users,
522
- roles
525
+ roles,
526
+ teams
523
527
  };
524
528
  };
525
529
 
@@ -1233,7 +1237,8 @@ var handleRBACUpdate = async (db, entityName, resourceId, rbacData, existingRbac
1233
1237
  }
1234
1238
  const {
1235
1239
  users = [],
1236
- roles = []
1240
+ roles = [],
1241
+ teams = []
1237
1242
  /* projects = [] */
1238
1243
  } = rbacData;
1239
1244
  if (!existingRbacRecords) {
@@ -1244,20 +1249,28 @@ var handleRBACUpdate = async (db, entityName, resourceId, rbacData, existingRbac
1244
1249
  }
1245
1250
  const newUserRecords = new Set(users.map((u) => `${u.id}:${u.rights}`));
1246
1251
  const newRoleRecords = new Set(roles.map((r) => `${r.id}:${r.rights}`));
1252
+ const newTeamRecords = new Set(teams.map((t) => `${t.id}:${t.rights}`));
1247
1253
  const existingUserRecords = new Set(
1248
1254
  existingRbacRecords.filter((r) => r.access_type === "User").map((r) => `${r.user_id}:${r.rights}`)
1249
1255
  );
1250
1256
  const existingRoleRecords = new Set(
1251
1257
  existingRbacRecords.filter((r) => r.access_type === "Role").map((r) => `${r.role_id}:${r.rights}`)
1252
1258
  );
1259
+ const existingTeamRecords = new Set(
1260
+ existingRbacRecords.filter((r) => r.access_type === "Team").map((r) => `${r.team_id}:${r.rights}`)
1261
+ );
1253
1262
  const usersToCreate = users.filter((u) => !existingUserRecords.has(`${u.id}:${u.rights}`));
1254
1263
  const rolesToCreate = roles.filter((r) => !existingRoleRecords.has(`${r.id}:${r.rights}`));
1264
+ const teamsToCreate = teams.filter((t) => !existingTeamRecords.has(`${t.id}:${t.rights}`));
1255
1265
  const usersToRemove = existingRbacRecords.filter(
1256
1266
  (r) => r.access_type === "User" && !newUserRecords.has(`${r.user_id}:${r.rights}`)
1257
1267
  );
1258
1268
  const rolesToRemove = existingRbacRecords.filter(
1259
1269
  (r) => r.access_type === "Role" && !newRoleRecords.has(`${r.role_id}:${r.rights}`)
1260
1270
  );
1271
+ const teamsToRemove = existingRbacRecords.filter(
1272
+ (r) => r.access_type === "Team" && !newTeamRecords.has(`${r.team_id}:${r.rights}`)
1273
+ );
1261
1274
  if (usersToRemove.length > 0) {
1262
1275
  await db.from("rbac").whereIn(
1263
1276
  "id",
@@ -1270,6 +1283,12 @@ var handleRBACUpdate = async (db, entityName, resourceId, rbacData, existingRbac
1270
1283
  rolesToRemove.map((r) => r.id)
1271
1284
  ).del();
1272
1285
  }
1286
+ if (teamsToRemove.length > 0) {
1287
+ await db.from("rbac").whereIn(
1288
+ "id",
1289
+ teamsToRemove.map((r) => r.id)
1290
+ ).del();
1291
+ }
1273
1292
  const recordsToInsert = [];
1274
1293
  usersToCreate.forEach((user) => {
1275
1294
  recordsToInsert.push({
@@ -1293,6 +1312,17 @@ var handleRBACUpdate = async (db, entityName, resourceId, rbacData, existingRbac
1293
1312
  updatedAt: /* @__PURE__ */ new Date()
1294
1313
  });
1295
1314
  });
1315
+ teamsToCreate.forEach((team) => {
1316
+ recordsToInsert.push({
1317
+ entity: entityName,
1318
+ access_type: "Team",
1319
+ target_resource_id: resourceId,
1320
+ team_id: team.id,
1321
+ rights: team.rights,
1322
+ createdAt: /* @__PURE__ */ new Date(),
1323
+ updatedAt: /* @__PURE__ */ new Date()
1324
+ });
1325
+ });
1296
1326
  if (recordsToInsert.length > 0) {
1297
1327
  await db.from("rbac").insert(recordsToInsert);
1298
1328
  }
@@ -1491,6 +1521,19 @@ function createMutations(table, providers, contexts, rerankers, tools, config) {
1491
1521
  }
1492
1522
  throw new Error("Insufficient role permissions to edit this record");
1493
1523
  }
1524
+ if (record.rights_mode === "teams" && user.team) {
1525
+ const rbacRecord = await db.from("rbac").where({
1526
+ entity: table.name.singular,
1527
+ target_resource_id: id,
1528
+ access_type: "Team",
1529
+ team_id: user.team,
1530
+ rights: "write"
1531
+ }).first();
1532
+ if (rbacRecord) {
1533
+ return true;
1534
+ }
1535
+ throw new Error("Insufficient team permissions to edit this record");
1536
+ }
1494
1537
  throw new Error("Insufficient permissions to edit this record");
1495
1538
  } catch (error) {
1496
1539
  console.error("Write access validation error:", error);
@@ -3177,7 +3220,7 @@ var processUiMessagesFlow = async ({
3177
3220
  modelId: agent.model,
3178
3221
  user,
3179
3222
  providers,
3180
- agent: { id: agent.id }
3223
+ agent
3181
3224
  });
3182
3225
  const providerapikey = resolved.apiKey;
3183
3226
  const resolvedLanguageModel = resolved.languageModel;
@@ -4209,6 +4252,8 @@ type LiteLLMModel {
4209
4252
  supports_function_calling: Boolean
4210
4253
  supports_pdf_input: Boolean
4211
4254
  supports_audio_input: Boolean
4255
+ input_cost_per_million_tokens: Float
4256
+ output_cost_per_million_tokens: Float
4212
4257
  }
4213
4258
  `;
4214
4259
  resolvers.Query["agentRateLimitUsage"] = async (_, args, context) => {
@@ -4264,7 +4309,7 @@ type LiteLLMModel {
4264
4309
  };
4265
4310
  };
4266
4311
  resolvers.Query["litellmCatalog"] = async () => {
4267
- const { fetchLiteLLMCatalog } = await import("./catalog-BWE6SLE2.js");
4312
+ const { fetchLiteLLMCatalog } = await import("./catalog-TBSPSN2N.js");
4268
4313
  return fetchLiteLLMCatalog();
4269
4314
  };
4270
4315
  resolvers.Query["workflowSchedule"] = async (_, args, context, info) => {
@@ -5781,7 +5826,7 @@ var ExuluProvider = class {
5781
5826
  modelId: agent.model,
5782
5827
  user,
5783
5828
  providers,
5784
- agent: { id: agent.id }
5829
+ agent
5785
5830
  });
5786
5831
  const providerapikey = resolved.apiKey;
5787
5832
  console.log(
@@ -7476,7 +7521,7 @@ var registerOpenAIGatewayRoutes = async (app, providers, tools, contexts, config
7476
7521
  });
7477
7522
  return;
7478
7523
  }
7479
- let project = null;
7524
+ let project = void 0;
7480
7525
  if (projectName) {
7481
7526
  let projectQuery = db("projects").select("*");
7482
7527
  projectQuery = applyAccessControl(projectsSchema3(), projectQuery, user);
@@ -7499,8 +7544,8 @@ var registerOpenAIGatewayRoutes = async (app, providers, tools, contexts, config
7499
7544
  modelId: agent.model,
7500
7545
  user,
7501
7546
  providers,
7502
- agent: { id: agent.id },
7503
- project: project ? { id: project.id } : void 0
7547
+ agent,
7548
+ project
7504
7549
  });
7505
7550
  } catch (err) {
7506
7551
  if (err instanceof ResolveModelError) {
@@ -7672,6 +7717,7 @@ var {
7672
7717
  rbacSchema,
7673
7718
  promptLibrarySchema,
7674
7719
  contextPresetsSchema,
7720
+ teamsSchema,
7675
7721
  embedderSettingsSchema,
7676
7722
  promptFavoritesSchema,
7677
7723
  statisticsSchema,
@@ -7721,6 +7767,7 @@ var createExpressRoutes = async (app, providers, tools, contexts, config, evals,
7721
7767
  jobResultsSchema(),
7722
7768
  promptLibrarySchema(),
7723
7769
  contextPresetsSchema(),
7770
+ teamsSchema(),
7724
7771
  embedderSettingsSchema(),
7725
7772
  promptFavoritesSchema(),
7726
7773
  evalRunsSchema(),
@@ -8107,7 +8154,7 @@ Mood: friendly and intelligent.
8107
8154
  modelId,
8108
8155
  user,
8109
8156
  providers,
8110
- agent: { id: agent.id }
8157
+ agent
8111
8158
  });
8112
8159
  } catch (err) {
8113
8160
  if (err instanceof ResolveModelError) {
@@ -8368,7 +8415,7 @@ ${customInstructions}` : agent.instructions;
8368
8415
  modelId: agent.model,
8369
8416
  user,
8370
8417
  providers,
8371
- agent: { id: agent.id }
8418
+ agent
8372
8419
  });
8373
8420
  } catch (err) {
8374
8421
  if (err instanceof ResolveModelError) {
@@ -9180,7 +9227,9 @@ ${style.markdown}` : params.prompt;
9180
9227
  project_id: project?.id,
9181
9228
  user_name: user.email,
9182
9229
  role_name: user.role?.name,
9183
- project_name: project?.name
9230
+ project_name: project?.name,
9231
+ team_id: user.team?.id,
9232
+ team_name: user.team?.name
9184
9233
  });
9185
9234
  if (tags?.length) {
9186
9235
  upstreamHeaders["x-litellm-tags"] = tags.join(",");
@@ -10217,7 +10266,7 @@ var ExuluMCP = class {
10217
10266
  modelId: agent.model,
10218
10267
  user,
10219
10268
  providers: allProviders,
10220
- agent: { id: agent.id }
10269
+ agent
10221
10270
  });
10222
10271
  const providerapikey = resolved.apiKey;
10223
10272
  if (!isLiteLLMEnabled()) {
@@ -11449,6 +11498,7 @@ var ExuluEval = class {
11449
11498
 
11450
11499
  // src/templates/evals/index.ts
11451
11500
  import { z as z4 } from "zod";
11501
+ import { generateText as generateText5, Output as Output2 } from "ai";
11452
11502
  var llmAsJudgeEval = () => {
11453
11503
  if (process.env.REDIS_HOST?.length && process.env.REDIS_PORT?.length) {
11454
11504
  return new ExuluEval({
@@ -11489,27 +11539,27 @@ var llmAsJudgeEval = () => {
11489
11539
  const resolved = await resolveModel({
11490
11540
  modelId: agent.model,
11491
11541
  providers: exuluApp.get().providers,
11492
- agent: { id: agent.id },
11542
+ agent,
11493
11543
  rbacBypass: true
11494
11544
  });
11495
- const providerapikey = resolved.apiKey;
11496
11545
  console.log("[EXULU] prompt", prompt);
11497
- const response = await provider.generateSync({
11498
- agent,
11499
- contexts: [],
11500
- rerankers: [],
11546
+ const { output } = await generateText5({
11547
+ temperature: 0,
11548
+ model: resolved.languageModel,
11549
+ system: "",
11501
11550
  prompt,
11502
- outputSchema: z4.object({
11503
- score: z4.number().min(0).max(100).describe("The score between 0 and 100.")
11504
- }),
11505
- languageModel: resolved.languageModel,
11506
- providerapikey
11551
+ maxRetries: 2,
11552
+ output: Output2.object({
11553
+ schema: z4.object({
11554
+ score: z4.number().min(0).max(100).describe("The score between 0 and 100.")
11555
+ })
11556
+ })
11507
11557
  });
11508
- console.log("[EXULU] response", response);
11509
- const score = parseFloat(response.score);
11558
+ console.log("[EXULU] output", output);
11559
+ const score = output.score;
11510
11560
  if (isNaN(score)) {
11511
11561
  throw new Error(
11512
- `Generated score from llm as a judge eval is not a number: ${response.score}`
11562
+ `Generated score from llm as a judge eval is not a number: ${output.score}`
11513
11563
  );
11514
11564
  }
11515
11565
  return score;
@@ -14634,6 +14684,7 @@ var {
14634
14684
  agentMessagesSchema: agentMessagesSchema2,
14635
14685
  modelsSchema: modelsSchema2,
14636
14686
  rolesSchema: rolesSchema2,
14687
+ teamsSchema: teamsSchema2,
14637
14688
  usersSchema: usersSchema2,
14638
14689
  skillsSchema: skillsSchema2,
14639
14690
  statisticsSchema: statisticsSchema2,
@@ -14676,6 +14727,7 @@ var up = async function(knex) {
14676
14727
  agentMessagesSchema2(),
14677
14728
  modelsSchema2(),
14678
14729
  rolesSchema2(),
14730
+ teamsSchema2(),
14679
14731
  testCasesSchema2(),
14680
14732
  evalSetsSchema2(),
14681
14733
  evalRunsSchema2(),
@@ -15691,7 +15743,7 @@ var MarkdownChunker = class {
15691
15743
  // ee/python/documents/processing/doc_processor.ts
15692
15744
  import * as fs4 from "fs";
15693
15745
  import * as path from "path";
15694
- import { generateText as generateText5, Output as Output2 } from "ai";
15746
+ import { generateText as generateText6, Output as Output3 } from "ai";
15695
15747
  import { z as z12 } from "zod";
15696
15748
  import pLimit from "p-limit";
15697
15749
  import { randomUUID as randomUUID6 } from "crypto";
@@ -16041,9 +16093,9 @@ If the page contains a flow-chart, schematic, technical drawing or control board
16041
16093
 
16042
16094
  ### 7. Only populate \`corrected_text\` when \`needs_correction\` is true. If the OCR output is accurate, return \`needs_correction: false\` and \`corrected_content: null\`.
16043
16095
  `;
16044
- const result = await generateText5({
16096
+ const result = await generateText6({
16045
16097
  model,
16046
- output: Output2.object({
16098
+ output: Output3.object({
16047
16099
  schema: z12.object({
16048
16100
  needs_correction: z12.boolean(),
16049
16101
  corrected_text: z12.string().nullable(),
@@ -9,6 +9,7 @@ export const RBACResolver = async (
9
9
  type: string;
10
10
  users: any[];
11
11
  roles: any[];
12
+ teams: any[];
12
13
  }> => {
13
14
 
14
15
  // If RBAC is not available
@@ -18,7 +19,8 @@ export const RBACResolver = async (
18
19
  return {
19
20
  type: "public",
20
21
  users: [],
21
- roles: []
22
+ roles: [],
23
+ teams: []
22
24
  }
23
25
  }
24
26
  // Get RBAC records for this resource
@@ -38,14 +40,20 @@ export const RBACResolver = async (
38
40
  .filter((r) => r.access_type === "Role")
39
41
  ?.map((r) => ({ id: r.role_id, rights: r.rights }));
40
42
 
43
+ const teams = rbacRecords
44
+ .filter((r) => r.access_type === "Team")
45
+ ?.map((r) => ({ id: r.team_id, rights: r.rights }));
46
+
41
47
  // Determine the type based on rights_mode or presence of records
42
48
  let type = rights_mode || "private";
43
49
  if (type === "users" && users.length === 0) type = "private";
44
50
  if (type === "roles" && roles.length === 0) type = "private";
51
+ if (type === "teams" && teams.length === 0) type = "private";
45
52
 
46
53
  return {
47
54
  type,
48
55
  users,
49
56
  roles,
57
+ teams,
50
58
  };
51
59
  };
package/ee/rbac-update.ts CHANGED
@@ -15,7 +15,7 @@ export const handleRBACUpdate = async (
15
15
  return;
16
16
  }
17
17
 
18
- const { users = [], roles = [] /* projects = [] */ } = rbacData;
18
+ const { users = [], roles = [], teams = [] /* projects = [] */ } = rbacData;
19
19
 
20
20
  // Get existing RBAC records if not provided
21
21
  if (!existingRbacRecords) {
@@ -31,6 +31,7 @@ export const handleRBACUpdate = async (
31
31
  // Create sets for comparison
32
32
  const newUserRecords = new Set(users.map((u: any) => `${u.id}:${u.rights}`));
33
33
  const newRoleRecords = new Set(roles.map((r: any) => `${r.id}:${r.rights}`));
34
+ const newTeamRecords = new Set(teams.map((t: any) => `${t.id}:${t.rights}`));
34
35
  // const newProjectRecords = new Set(projects.map((p: any) => `${p.id}:${p.rights}`));
35
36
  const existingUserRecords = new Set(
36
37
  existingRbacRecords
@@ -42,10 +43,16 @@ export const handleRBACUpdate = async (
42
43
  .filter((r) => r.access_type === "Role")
43
44
  .map((r) => `${r.role_id}:${r.rights}`),
44
45
  );
46
+ const existingTeamRecords = new Set(
47
+ existingRbacRecords
48
+ .filter((r) => r.access_type === "Team")
49
+ .map((r) => `${r.team_id}:${r.rights}`),
50
+ );
45
51
 
46
52
  // Records to create
47
53
  const usersToCreate = users.filter((u: any) => !existingUserRecords.has(`${u.id}:${u.rights}`));
48
54
  const rolesToCreate = roles.filter((r: any) => !existingRoleRecords.has(`${r.id}:${r.rights}`));
55
+ const teamsToCreate = teams.filter((t: any) => !existingTeamRecords.has(`${t.id}:${t.rights}`));
49
56
  // const projectsToCreate = projects.filter((p: any) => !existingProjectRecords.has(`${p.id}:${p.rights}`));
50
57
 
51
58
  // Records to remove
@@ -55,6 +62,9 @@ export const handleRBACUpdate = async (
55
62
  const rolesToRemove = existingRbacRecords.filter(
56
63
  (r) => r.access_type === "Role" && !newRoleRecords.has(`${r.role_id}:${r.rights}`),
57
64
  );
65
+ const teamsToRemove = existingRbacRecords.filter(
66
+ (r) => r.access_type === "Team" && !newTeamRecords.has(`${r.team_id}:${r.rights}`),
67
+ );
58
68
  // const projectsToRemove = existingRbacRecords
59
69
  // .filter(r => r.access_type === 'Project' && !newProjectRecords.has(`${r.project_id}:${r.rights}`));
60
70
 
@@ -77,6 +87,15 @@ export const handleRBACUpdate = async (
77
87
  )
78
88
  .del();
79
89
  }
90
+ if (teamsToRemove.length > 0) {
91
+ await db
92
+ .from("rbac")
93
+ .whereIn(
94
+ "id",
95
+ teamsToRemove.map((r) => r.id),
96
+ )
97
+ .del();
98
+ }
80
99
 
81
100
  // Create new records
82
101
  const recordsToInsert: any[] = [];
@@ -105,6 +124,18 @@ export const handleRBACUpdate = async (
105
124
  });
106
125
  });
107
126
 
127
+ teamsToCreate.forEach((team: any) => {
128
+ recordsToInsert.push({
129
+ entity: entityName,
130
+ access_type: "Team",
131
+ target_resource_id: resourceId,
132
+ team_id: team.id,
133
+ rights: team.rights,
134
+ createdAt: new Date(),
135
+ updatedAt: new Date(),
136
+ });
137
+ });
138
+
108
139
  if (recordsToInsert.length > 0) {
109
140
  await db.from("rbac").insert(recordsToInsert);
110
141
  }
package/ee/schemas.ts CHANGED
@@ -76,6 +76,27 @@ export const rolesSchema: ExuluTableDefinition = {
76
76
  ],
77
77
  };
78
78
 
79
+ export const teamsSchema: ExuluTableDefinition = {
80
+ type: "teams",
81
+ name: {
82
+ plural: "teams",
83
+ singular: "team",
84
+ },
85
+ fields: [
86
+ {
87
+ name: "name",
88
+ type: "text",
89
+ index: true,
90
+ unique: true,
91
+ required: true,
92
+ },
93
+ {
94
+ name: "description",
95
+ type: "text",
96
+ },
97
+ ],
98
+ };
99
+
79
100
  export const statisticsSchema: ExuluTableDefinition = {
80
101
  type: "tracking",
81
102
  name: {
@@ -301,6 +322,10 @@ export const rbacSchema: ExuluTableDefinition = {
301
322
  name: "role_id",
302
323
  type: "uuid",
303
324
  },
325
+ {
326
+ name: "team_id",
327
+ type: "uuid",
328
+ },
304
329
  {
305
330
  name: "user_id",
306
331
  type: "number",
package/ee/workers.ts CHANGED
@@ -1390,7 +1390,7 @@ export const processUiMessagesFlow = async ({
1390
1390
  modelId: agent.model,
1391
1391
  user,
1392
1392
  providers,
1393
- agent: { id: agent.id },
1393
+ agent: agent
1394
1394
  });
1395
1395
  const providerapikey = resolved.apiKey;
1396
1396
  const resolvedLanguageModel = resolved.languageModel;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@exulu/backend",
3
3
  "author": "Qventu Bv.",
4
- "version": "1.62.1",
4
+ "version": "1.63.0",
5
5
  "main": "./dist/index.js",
6
6
  "private": false,
7
7
  "publishConfig": {