@exulu/backend 1.21.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
- # [1.21.0](https://github.com/Qventu/exulu-backend/compare/v1.20.0...v1.21.0) (2025-08-30)
1
+ # [1.22.0](https://github.com/Qventu/exulu-backend/compare/v1.21.0...v1.22.0) (2025-09-03)
2
2
 
3
3
 
4
4
  ### Features
5
5
 
6
- * items as graphql endpoints ([ceca823](https://github.com/Qventu/exulu-backend/commit/ceca8236e788bda71786c1445836875aa4d644a5))
6
+ * improved UI layout for chat interface ([4802a3c](https://github.com/Qventu/exulu-backend/commit/4802a3c0ac3eb21fc6a0f492f8786de341bd7103))
package/dist/index.cjs CHANGED
@@ -2583,7 +2583,7 @@ var vectorSearch = async ({
2583
2583
  items
2584
2584
  };
2585
2585
  };
2586
- var RBACResolver = async (db3, table, entityName, resourceId, rights_mode) => {
2586
+ var RBACResolver = async (db3, entityName, resourceId, rights_mode) => {
2587
2587
  const rbacRecords = await db3.from("rbac").where({
2588
2588
  entity: entityName,
2589
2589
  target_resource_id: resourceId
@@ -2821,7 +2821,7 @@ type PageInfo {
2821
2821
  const resourceId = parent.id;
2822
2822
  const entityName = table.name.singular;
2823
2823
  const rights_mode = parent.rights_mode;
2824
- return RBACResolver(db3, table, entityName, resourceId, rights_mode);
2824
+ return RBACResolver(db3, entityName, resourceId, rights_mode);
2825
2825
  };
2826
2826
  }
2827
2827
  }
@@ -3319,8 +3319,6 @@ var ExuluAgent2 = class {
3319
3319
  // append the new message to the previous messages:
3320
3320
  messages: [...previousMessagesContent, message]
3321
3321
  });
3322
- console.log("[EXULU] Model provider key", providerApiKey);
3323
- console.log("[EXULU] Tool configs", toolConfigs);
3324
3322
  const result = (0, import_ai.streamText)({
3325
3323
  model,
3326
3324
  // Should be a LanguageModelV1
@@ -3344,11 +3342,13 @@ var ExuluAgent2 = class {
3344
3342
  "[EXULU] chat stream finished.",
3345
3343
  messages2
3346
3344
  );
3347
- await saveChat({
3348
- session,
3349
- user,
3350
- messages: messages2
3351
- });
3345
+ if (session) {
3346
+ await saveChat({
3347
+ session,
3348
+ user,
3349
+ messages: messages2
3350
+ });
3351
+ }
3352
3352
  if (statistics) {
3353
3353
  await updateStatistic({
3354
3354
  name: "count",
@@ -4904,6 +4904,8 @@ Mood: friendly and intelligent.
4904
4904
  const agentInstance = await db3.from("agents").where({
4905
4905
  id: instance
4906
4906
  }).first();
4907
+ const agentRbac = await RBACResolver(db3, "agent", agentInstance.id, agentInstance.rights_mode || "private");
4908
+ agentInstance.RBAC = agentRbac;
4907
4909
  if (!agentInstance) {
4908
4910
  res.status(400).json({
4909
4911
  message: "Agent instance not found."
@@ -4942,6 +4944,86 @@ Mood: friendly and intelligent.
4942
4944
  return;
4943
4945
  }
4944
4946
  const user = authenticationResult.user;
4947
+ const agentIsPublic = agentInstance.rights_mode === "public";
4948
+ const agentByUsers = agentInstance.rights_mode === "users";
4949
+ const agentByRoles = agentInstance.rights_mode === "roles";
4950
+ const isAgentCreator = agentInstance.created_by === user.id;
4951
+ const isAdmin = user.super_admin;
4952
+ const isApi = user.type === "api";
4953
+ let hasAccessToAgent = "none";
4954
+ if (agentIsPublic || isAgentCreator || isAdmin || isApi) {
4955
+ hasAccessToAgent = "write";
4956
+ }
4957
+ if (agentByUsers) {
4958
+ hasAccessToAgent = agentInstance.RBAC?.users?.find((x) => x.id === user.id)?.rights || "none";
4959
+ if (!hasAccessToAgent || hasAccessToAgent === "none" || hasAccessToAgent === "read") {
4960
+ res.status(410).json({
4961
+ message: `Your current user ${user.id} does not have access to this agent.`
4962
+ });
4963
+ return;
4964
+ }
4965
+ }
4966
+ if (agentByRoles) {
4967
+ hasAccessToAgent = agentInstance.RBAC?.roles?.find((x) => x.id === user.role?.id)?.rights || "none";
4968
+ if (!hasAccessToAgent || hasAccessToAgent === "none" || hasAccessToAgent === "read") {
4969
+ res.status(410).json({
4970
+ message: `Your current role ${user.role?.name} does not have access to this agent.`
4971
+ });
4972
+ return;
4973
+ }
4974
+ }
4975
+ let hasAccessToSession = "none";
4976
+ ;
4977
+ if (headers.session) {
4978
+ const session = await db3.from("agents").where({
4979
+ id: instance
4980
+ }).first();
4981
+ const sessionIsPublic = agentInstance.rights_mode === "public";
4982
+ const sessionByUsers = agentInstance.rights_mode === "users";
4983
+ const sessionByRoles = agentInstance.rights_mode === "roles";
4984
+ const isSessionCreator = agentInstance.created_by === user.id;
4985
+ const isAdmin2 = user.super_admin;
4986
+ const isApi2 = user.type === "api";
4987
+ if (sessionIsPublic || isSessionCreator || isAdmin2 || isApi2) {
4988
+ hasAccessToSession = "write";
4989
+ }
4990
+ if (sessionByUsers) {
4991
+ hasAccessToSession = session.RBAC?.users?.find((x) => x.id === user.id)?.rights || "none";
4992
+ if (!hasAccessToSession || hasAccessToSession === "none" || hasAccessToSession === "read") {
4993
+ res.status(410).json({
4994
+ message: `Your current user ${user.id} does not have access to this session.`
4995
+ });
4996
+ return;
4997
+ }
4998
+ }
4999
+ if (sessionByRoles) {
5000
+ hasAccessToSession = session.RBAC?.roles?.find((x) => x.id === user.role?.id)?.rights || "none";
5001
+ if (!hasAccessToSession || hasAccessToSession === "none" || hasAccessToSession === "read") {
5002
+ res.status(410).json({
5003
+ message: `Your current role ${user.role?.name} does not have access to this session.`
5004
+ });
5005
+ return;
5006
+ }
5007
+ }
5008
+ }
5009
+ if (!hasAccessToAgent || hasAccessToAgent === "none") {
5010
+ res.status(410).json({
5011
+ message: "You don't have access to this agent."
5012
+ });
5013
+ return;
5014
+ }
5015
+ if (!hasAccessToSession || hasAccessToSession === "none") {
5016
+ res.status(410).json({
5017
+ message: "You don't have access to this session."
5018
+ });
5019
+ return;
5020
+ }
5021
+ if (headers.session && !hasAccessToSession) {
5022
+ res.status(410).json({
5023
+ message: "You don't have access to this session."
5024
+ });
5025
+ return;
5026
+ }
4945
5027
  if (user.type !== "api" && !user.super_admin && req.body.resourceId !== user.id) {
4946
5028
  res.status(400).json({
4947
5029
  message: "The provided user id in the resourceId field is not the same as the authenticated user. Only super admins and API users can impersonate other users."
package/dist/index.d.cts CHANGED
@@ -245,20 +245,21 @@ interface ExuluWorkflow {
245
245
  id: string;
246
246
  name: string;
247
247
  description?: string;
248
- rights_mode?: 'private' | 'users' | 'roles' | 'public';
249
- RBAC?: {
250
- users?: Array<{
251
- id: string;
252
- rights: 'read' | 'write';
253
- }>;
254
- roles?: Array<{
255
- id: string;
256
- rights: 'read' | 'write';
257
- }>;
258
- };
248
+ rights_mode?: ExuluRightsMode;
249
+ RBAC?: ExuluRBAC;
259
250
  variables?: WorkflowVariable[];
260
251
  steps_json?: WorkflowStep[];
261
252
  }
253
+ interface ExuluRBAC {
254
+ users?: Array<{
255
+ id: string;
256
+ rights: 'read' | 'write';
257
+ }>;
258
+ roles?: Array<{
259
+ id: string;
260
+ rights: 'read' | 'write';
261
+ }>;
262
+ }
262
263
  type ExuluEvalRunnerInstance = {
263
264
  name: string;
264
265
  description: string;
package/dist/index.d.ts CHANGED
@@ -245,20 +245,21 @@ interface ExuluWorkflow {
245
245
  id: string;
246
246
  name: string;
247
247
  description?: string;
248
- rights_mode?: 'private' | 'users' | 'roles' | 'public';
249
- RBAC?: {
250
- users?: Array<{
251
- id: string;
252
- rights: 'read' | 'write';
253
- }>;
254
- roles?: Array<{
255
- id: string;
256
- rights: 'read' | 'write';
257
- }>;
258
- };
248
+ rights_mode?: ExuluRightsMode;
249
+ RBAC?: ExuluRBAC;
259
250
  variables?: WorkflowVariable[];
260
251
  steps_json?: WorkflowStep[];
261
252
  }
253
+ interface ExuluRBAC {
254
+ users?: Array<{
255
+ id: string;
256
+ rights: 'read' | 'write';
257
+ }>;
258
+ roles?: Array<{
259
+ id: string;
260
+ rights: 'read' | 'write';
261
+ }>;
262
+ }
262
263
  type ExuluEvalRunnerInstance = {
263
264
  name: string;
264
265
  description: string;
package/dist/index.js CHANGED
@@ -2542,7 +2542,7 @@ var vectorSearch = async ({
2542
2542
  items
2543
2543
  };
2544
2544
  };
2545
- var RBACResolver = async (db3, table, entityName, resourceId, rights_mode) => {
2545
+ var RBACResolver = async (db3, entityName, resourceId, rights_mode) => {
2546
2546
  const rbacRecords = await db3.from("rbac").where({
2547
2547
  entity: entityName,
2548
2548
  target_resource_id: resourceId
@@ -2780,7 +2780,7 @@ type PageInfo {
2780
2780
  const resourceId = parent.id;
2781
2781
  const entityName = table.name.singular;
2782
2782
  const rights_mode = parent.rights_mode;
2783
- return RBACResolver(db3, table, entityName, resourceId, rights_mode);
2783
+ return RBACResolver(db3, entityName, resourceId, rights_mode);
2784
2784
  };
2785
2785
  }
2786
2786
  }
@@ -3278,8 +3278,6 @@ var ExuluAgent2 = class {
3278
3278
  // append the new message to the previous messages:
3279
3279
  messages: [...previousMessagesContent, message]
3280
3280
  });
3281
- console.log("[EXULU] Model provider key", providerApiKey);
3282
- console.log("[EXULU] Tool configs", toolConfigs);
3283
3281
  const result = streamText({
3284
3282
  model,
3285
3283
  // Should be a LanguageModelV1
@@ -3303,11 +3301,13 @@ var ExuluAgent2 = class {
3303
3301
  "[EXULU] chat stream finished.",
3304
3302
  messages2
3305
3303
  );
3306
- await saveChat({
3307
- session,
3308
- user,
3309
- messages: messages2
3310
- });
3304
+ if (session) {
3305
+ await saveChat({
3306
+ session,
3307
+ user,
3308
+ messages: messages2
3309
+ });
3310
+ }
3311
3311
  if (statistics) {
3312
3312
  await updateStatistic({
3313
3313
  name: "count",
@@ -4863,6 +4863,8 @@ Mood: friendly and intelligent.
4863
4863
  const agentInstance = await db3.from("agents").where({
4864
4864
  id: instance
4865
4865
  }).first();
4866
+ const agentRbac = await RBACResolver(db3, "agent", agentInstance.id, agentInstance.rights_mode || "private");
4867
+ agentInstance.RBAC = agentRbac;
4866
4868
  if (!agentInstance) {
4867
4869
  res.status(400).json({
4868
4870
  message: "Agent instance not found."
@@ -4901,6 +4903,86 @@ Mood: friendly and intelligent.
4901
4903
  return;
4902
4904
  }
4903
4905
  const user = authenticationResult.user;
4906
+ const agentIsPublic = agentInstance.rights_mode === "public";
4907
+ const agentByUsers = agentInstance.rights_mode === "users";
4908
+ const agentByRoles = agentInstance.rights_mode === "roles";
4909
+ const isAgentCreator = agentInstance.created_by === user.id;
4910
+ const isAdmin = user.super_admin;
4911
+ const isApi = user.type === "api";
4912
+ let hasAccessToAgent = "none";
4913
+ if (agentIsPublic || isAgentCreator || isAdmin || isApi) {
4914
+ hasAccessToAgent = "write";
4915
+ }
4916
+ if (agentByUsers) {
4917
+ hasAccessToAgent = agentInstance.RBAC?.users?.find((x) => x.id === user.id)?.rights || "none";
4918
+ if (!hasAccessToAgent || hasAccessToAgent === "none" || hasAccessToAgent === "read") {
4919
+ res.status(410).json({
4920
+ message: `Your current user ${user.id} does not have access to this agent.`
4921
+ });
4922
+ return;
4923
+ }
4924
+ }
4925
+ if (agentByRoles) {
4926
+ hasAccessToAgent = agentInstance.RBAC?.roles?.find((x) => x.id === user.role?.id)?.rights || "none";
4927
+ if (!hasAccessToAgent || hasAccessToAgent === "none" || hasAccessToAgent === "read") {
4928
+ res.status(410).json({
4929
+ message: `Your current role ${user.role?.name} does not have access to this agent.`
4930
+ });
4931
+ return;
4932
+ }
4933
+ }
4934
+ let hasAccessToSession = "none";
4935
+ ;
4936
+ if (headers.session) {
4937
+ const session = await db3.from("agents").where({
4938
+ id: instance
4939
+ }).first();
4940
+ const sessionIsPublic = agentInstance.rights_mode === "public";
4941
+ const sessionByUsers = agentInstance.rights_mode === "users";
4942
+ const sessionByRoles = agentInstance.rights_mode === "roles";
4943
+ const isSessionCreator = agentInstance.created_by === user.id;
4944
+ const isAdmin2 = user.super_admin;
4945
+ const isApi2 = user.type === "api";
4946
+ if (sessionIsPublic || isSessionCreator || isAdmin2 || isApi2) {
4947
+ hasAccessToSession = "write";
4948
+ }
4949
+ if (sessionByUsers) {
4950
+ hasAccessToSession = session.RBAC?.users?.find((x) => x.id === user.id)?.rights || "none";
4951
+ if (!hasAccessToSession || hasAccessToSession === "none" || hasAccessToSession === "read") {
4952
+ res.status(410).json({
4953
+ message: `Your current user ${user.id} does not have access to this session.`
4954
+ });
4955
+ return;
4956
+ }
4957
+ }
4958
+ if (sessionByRoles) {
4959
+ hasAccessToSession = session.RBAC?.roles?.find((x) => x.id === user.role?.id)?.rights || "none";
4960
+ if (!hasAccessToSession || hasAccessToSession === "none" || hasAccessToSession === "read") {
4961
+ res.status(410).json({
4962
+ message: `Your current role ${user.role?.name} does not have access to this session.`
4963
+ });
4964
+ return;
4965
+ }
4966
+ }
4967
+ }
4968
+ if (!hasAccessToAgent || hasAccessToAgent === "none") {
4969
+ res.status(410).json({
4970
+ message: "You don't have access to this agent."
4971
+ });
4972
+ return;
4973
+ }
4974
+ if (!hasAccessToSession || hasAccessToSession === "none") {
4975
+ res.status(410).json({
4976
+ message: "You don't have access to this session."
4977
+ });
4978
+ return;
4979
+ }
4980
+ if (headers.session && !hasAccessToSession) {
4981
+ res.status(410).json({
4982
+ message: "You don't have access to this session."
4983
+ });
4984
+ return;
4985
+ }
4904
4986
  if (user.type !== "api" && !user.super_admin && req.body.resourceId !== user.id) {
4905
4987
  res.status(400).json({
4906
4988
  message: "The provided user id in the resourceId field is not the same as the authenticated user. Only super admins and API users can impersonate other users."
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@exulu/backend",
3
3
  "author": "Qventu Bv.",
4
- "version": "1.21.0",
4
+ "version": "1.22.0",
5
5
  "main": "./dist/index.js",
6
6
  "private": false,
7
7
  "publishConfig": {
@@ -6,6 +6,13 @@ export interface AgentSession {
6
6
  agentId: string;
7
7
  resourceId: string;
8
8
  title: string;
9
+ created_by: string;
10
+ rights_mode: 'private' | 'users' | 'roles' | 'public' | 'project'
11
+ RBAC?: {
12
+ type?: string;
13
+ users?: Array<{ id: string; rights: 'read' | 'write' }>;
14
+ roles?: Array<{ id: string; rights: 'read' | 'write' }>;
15
+ };
9
16
  }
10
17
  export interface AgentMessage {
11
18
  id: string;
@@ -38,6 +38,7 @@ export interface Agent {
38
38
  }
39
39
  // New RBAC fields
40
40
  rights_mode?: 'private' | 'users' | 'roles' | 'public';
41
+ created_by?: string;
41
42
  RBAC?: {
42
43
  type?: string;
43
44
  users?: Array<{ id: string; rights: 'read' | 'write' }>;