@exulu/backend 1.14.1 → 1.16.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 +3 -3
- package/dist/index.cjs +177 -32
- package/dist/index.d.cts +16 -8
- package/dist/index.d.ts +16 -8
- package/dist/index.js +177 -32
- package/package.json +5 -15
- package/types/models/agent.ts +1 -0
- package/types/models/user.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
# [1.16.0](https://github.com/Qventu/exulu-backend/compare/v1.15.0...v1.16.0) (2025-08-23)
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
###
|
|
4
|
+
### Features
|
|
5
5
|
|
|
6
|
-
*
|
|
6
|
+
* add user and role to statistics ([f9c6d84](https://github.com/Qventu/exulu-backend/commit/f9c6d84a8cf4b5c32a2d5935bf9074fc6960f10b))
|
|
7
7
|
|
|
8
8
|
# [1.1.0](https://github.com/Qventu/exulu-backend/compare/v1.0.1...v1.1.0) (2025-07-30)
|
|
9
9
|
|
package/dist/index.cjs
CHANGED
|
@@ -478,7 +478,7 @@ function sanitizeToolName(name) {
|
|
|
478
478
|
}
|
|
479
479
|
return sanitized;
|
|
480
480
|
}
|
|
481
|
-
var convertToolsArrayToObject = (tools, configs, providerApiKey) => {
|
|
481
|
+
var convertToolsArrayToObject = (tools, configs, providerApiKey, user, role) => {
|
|
482
482
|
if (!tools) return {};
|
|
483
483
|
const sanitizedTools = tools ? tools.map((tool2) => ({
|
|
484
484
|
...tool2,
|
|
@@ -513,6 +513,8 @@ var convertToolsArrayToObject = (tools, configs, providerApiKey) => {
|
|
|
513
513
|
// is available, after we added the .value property
|
|
514
514
|
// by hydrating it from the variables table.
|
|
515
515
|
providerApiKey,
|
|
516
|
+
user,
|
|
517
|
+
role,
|
|
516
518
|
config: config ? config.config.reduce((acc, curr) => {
|
|
517
519
|
acc[curr.name] = curr.value;
|
|
518
520
|
return acc;
|
|
@@ -589,6 +591,7 @@ var ExuluAgent = class {
|
|
|
589
591
|
this.config = config;
|
|
590
592
|
this.type = type;
|
|
591
593
|
this.capabilities = capabilities || {
|
|
594
|
+
text: false,
|
|
592
595
|
images: [],
|
|
593
596
|
files: [],
|
|
594
597
|
audio: [],
|
|
@@ -617,10 +620,12 @@ var ExuluAgent = class {
|
|
|
617
620
|
}),
|
|
618
621
|
description: `A function that calls an AI agent named: ${this.name}. The agent does the following: ${this.description}.`,
|
|
619
622
|
config: [],
|
|
620
|
-
execute: async ({ prompt, config, providerApiKey }) => {
|
|
623
|
+
execute: async ({ prompt, config, providerApiKey, user, role }) => {
|
|
621
624
|
return await this.generateSync({
|
|
622
625
|
prompt,
|
|
623
626
|
providerApiKey,
|
|
627
|
+
user,
|
|
628
|
+
role,
|
|
624
629
|
statistics: {
|
|
625
630
|
label: "",
|
|
626
631
|
trigger: "tool"
|
|
@@ -629,7 +634,7 @@ var ExuluAgent = class {
|
|
|
629
634
|
}
|
|
630
635
|
});
|
|
631
636
|
};
|
|
632
|
-
generateSync = async ({ prompt, user, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
637
|
+
generateSync = async ({ prompt, user, role, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
633
638
|
if (!this.model) {
|
|
634
639
|
throw new Error("Model is required for streaming.");
|
|
635
640
|
}
|
|
@@ -665,7 +670,7 @@ var ExuluAgent = class {
|
|
|
665
670
|
messages: messages ? (0, import_ai.convertToModelMessages)(messages) : void 0,
|
|
666
671
|
prompt,
|
|
667
672
|
maxRetries: 2,
|
|
668
|
-
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey),
|
|
673
|
+
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey, user, role),
|
|
669
674
|
stopWhen: [(0, import_ai.stepCountIs)(5)]
|
|
670
675
|
});
|
|
671
676
|
if (statistics) {
|
|
@@ -674,12 +679,14 @@ var ExuluAgent = class {
|
|
|
674
679
|
label: statistics.label,
|
|
675
680
|
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
676
681
|
trigger: statistics.trigger,
|
|
677
|
-
count: 1
|
|
682
|
+
count: 1,
|
|
683
|
+
user,
|
|
684
|
+
role
|
|
678
685
|
});
|
|
679
686
|
}
|
|
680
687
|
return text;
|
|
681
688
|
};
|
|
682
|
-
generateStream = async ({ express: express3, user, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
689
|
+
generateStream = async ({ express: express3, user, role, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
683
690
|
if (!this.model) {
|
|
684
691
|
throw new Error("Model is required for streaming.");
|
|
685
692
|
}
|
|
@@ -712,7 +719,7 @@ var ExuluAgent = class {
|
|
|
712
719
|
messages: messages ? (0, import_ai.convertToModelMessages)(messages) : void 0,
|
|
713
720
|
system: "You are a helpful assistant. When you use a tool to answer a question do not explicitly comment on the result of the tool call unless the user has explicitly you to do something with the result.",
|
|
714
721
|
maxRetries: 2,
|
|
715
|
-
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey),
|
|
722
|
+
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey, user, role),
|
|
716
723
|
onError: (error) => console.error("[EXULU] chat stream error.", error),
|
|
717
724
|
stopWhen: [(0, import_ai.stepCountIs)(5)]
|
|
718
725
|
});
|
|
@@ -740,7 +747,9 @@ var ExuluAgent = class {
|
|
|
740
747
|
label: statistics.label,
|
|
741
748
|
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
742
749
|
trigger: statistics.trigger,
|
|
743
|
-
count: 1
|
|
750
|
+
count: 1,
|
|
751
|
+
user,
|
|
752
|
+
role
|
|
744
753
|
});
|
|
745
754
|
}
|
|
746
755
|
}
|
|
@@ -784,14 +793,16 @@ var ExuluEmbedder = class {
|
|
|
784
793
|
this.queue = queue;
|
|
785
794
|
this.generateEmbeddings = generateEmbeddings;
|
|
786
795
|
}
|
|
787
|
-
async generateFromQuery(query, statistics) {
|
|
796
|
+
async generateFromQuery(query, statistics, user, role) {
|
|
788
797
|
if (statistics) {
|
|
789
798
|
await updateStatistic({
|
|
790
799
|
name: "count",
|
|
791
800
|
label: statistics.label,
|
|
792
801
|
type: STATISTICS_TYPE_ENUM.EMBEDDER_GENERATE,
|
|
793
802
|
trigger: statistics.trigger,
|
|
794
|
-
count: 1
|
|
803
|
+
count: 1,
|
|
804
|
+
user,
|
|
805
|
+
role
|
|
795
806
|
});
|
|
796
807
|
}
|
|
797
808
|
return await this.generateEmbeddings({
|
|
@@ -804,14 +815,16 @@ var ExuluEmbedder = class {
|
|
|
804
815
|
}]
|
|
805
816
|
});
|
|
806
817
|
}
|
|
807
|
-
async generateFromDocument(input, statistics) {
|
|
818
|
+
async generateFromDocument(input, statistics, user, role) {
|
|
808
819
|
if (statistics) {
|
|
809
820
|
await updateStatistic({
|
|
810
821
|
name: "count",
|
|
811
822
|
label: statistics.label,
|
|
812
823
|
type: STATISTICS_TYPE_ENUM.EMBEDDER_GENERATE,
|
|
813
824
|
trigger: statistics.trigger,
|
|
814
|
-
count: 1
|
|
825
|
+
count: 1,
|
|
826
|
+
user,
|
|
827
|
+
role
|
|
815
828
|
});
|
|
816
829
|
}
|
|
817
830
|
if (!this.chunker) {
|
|
@@ -1065,7 +1078,7 @@ var ExuluContext = class {
|
|
|
1065
1078
|
const tableExists = await db3.schema.hasTable(this.getTableName());
|
|
1066
1079
|
return tableExists;
|
|
1067
1080
|
};
|
|
1068
|
-
async updateItem(user, id, item) {
|
|
1081
|
+
async updateItem(user, id, item, role) {
|
|
1069
1082
|
if (!id) {
|
|
1070
1083
|
throw new Error("Id is required for updating an item.");
|
|
1071
1084
|
}
|
|
@@ -1106,7 +1119,7 @@ var ExuluContext = class {
|
|
|
1106
1119
|
}, {
|
|
1107
1120
|
label: this.name,
|
|
1108
1121
|
trigger: "agent"
|
|
1109
|
-
});
|
|
1122
|
+
}, user, role);
|
|
1110
1123
|
const exists = await db3.schema.hasTable(this.getChunksTableName());
|
|
1111
1124
|
if (!exists) {
|
|
1112
1125
|
await this.createChunksTable();
|
|
@@ -1127,7 +1140,7 @@ var ExuluContext = class {
|
|
|
1127
1140
|
job: void 0
|
|
1128
1141
|
};
|
|
1129
1142
|
}
|
|
1130
|
-
async insertItem(user, item, upsert = false) {
|
|
1143
|
+
async insertItem(user, item, upsert = false, role) {
|
|
1131
1144
|
if (!item.name) {
|
|
1132
1145
|
throw new Error("Name field is required.");
|
|
1133
1146
|
}
|
|
@@ -1138,14 +1151,14 @@ var ExuluContext = class {
|
|
|
1138
1151
|
throw new Error("Item with external id " + item.external_id + " already exists.");
|
|
1139
1152
|
}
|
|
1140
1153
|
if (existingItem && upsert) {
|
|
1141
|
-
await this.updateItem(user, existingItem.id, item);
|
|
1154
|
+
await this.updateItem(user, existingItem.id, item, role);
|
|
1142
1155
|
return existingItem.id;
|
|
1143
1156
|
}
|
|
1144
1157
|
}
|
|
1145
1158
|
if (upsert && item.id) {
|
|
1146
1159
|
const existingItem = await db3.from(this.getTableName()).where({ id: item.id }).first();
|
|
1147
1160
|
if (existingItem && upsert) {
|
|
1148
|
-
await this.updateItem(user, existingItem.id, item);
|
|
1161
|
+
await this.updateItem(user, existingItem.id, item, role);
|
|
1149
1162
|
return existingItem.id;
|
|
1150
1163
|
}
|
|
1151
1164
|
}
|
|
@@ -1189,7 +1202,7 @@ var ExuluContext = class {
|
|
|
1189
1202
|
}, {
|
|
1190
1203
|
label: this.name,
|
|
1191
1204
|
trigger: "agent"
|
|
1192
|
-
});
|
|
1205
|
+
}, user, role);
|
|
1193
1206
|
const exists = await db3.schema.hasTable(this.getChunksTableName());
|
|
1194
1207
|
if (!exists) {
|
|
1195
1208
|
await this.createChunksTable();
|
|
@@ -1217,6 +1230,8 @@ var ExuluContext = class {
|
|
|
1217
1230
|
order,
|
|
1218
1231
|
page,
|
|
1219
1232
|
name,
|
|
1233
|
+
user,
|
|
1234
|
+
role,
|
|
1220
1235
|
archived,
|
|
1221
1236
|
query,
|
|
1222
1237
|
method
|
|
@@ -1285,7 +1300,9 @@ var ExuluContext = class {
|
|
|
1285
1300
|
name: "count",
|
|
1286
1301
|
label: statistics.label,
|
|
1287
1302
|
type: STATISTICS_TYPE_ENUM.CONTEXT_RETRIEVE,
|
|
1288
|
-
trigger: statistics.trigger
|
|
1303
|
+
trigger: statistics.trigger,
|
|
1304
|
+
user,
|
|
1305
|
+
role
|
|
1289
1306
|
});
|
|
1290
1307
|
}
|
|
1291
1308
|
if (this.queryRewriter) {
|
|
@@ -1301,7 +1318,10 @@ var ExuluContext = class {
|
|
|
1301
1318
|
itemsQuery.select(chunksTable + ".chunk_index");
|
|
1302
1319
|
itemsQuery.select(chunksTable + ".created_at as chunk_created_at");
|
|
1303
1320
|
itemsQuery.select(chunksTable + ".updated_at as chunk_updated_at");
|
|
1304
|
-
const { chunks } = await this.embedder.generateFromQuery(query
|
|
1321
|
+
const { chunks } = await this.embedder.generateFromQuery(query, {
|
|
1322
|
+
label: this.name,
|
|
1323
|
+
trigger: "agent"
|
|
1324
|
+
}, user, role);
|
|
1305
1325
|
if (!chunks?.[0]?.vector) {
|
|
1306
1326
|
throw new Error("No vector generated for query.");
|
|
1307
1327
|
}
|
|
@@ -1449,11 +1469,13 @@ var ExuluContext = class {
|
|
|
1449
1469
|
}),
|
|
1450
1470
|
config: [],
|
|
1451
1471
|
description: `Gets information from the context called: ${this.name}. The context description is: ${this.description}.`,
|
|
1452
|
-
execute: async ({ query }) => {
|
|
1472
|
+
execute: async ({ query, user, role }) => {
|
|
1453
1473
|
return await this.getItems({
|
|
1454
1474
|
page: 1,
|
|
1455
1475
|
limit: 10,
|
|
1456
1476
|
query,
|
|
1477
|
+
user,
|
|
1478
|
+
role,
|
|
1457
1479
|
statistics: {
|
|
1458
1480
|
label: this.name,
|
|
1459
1481
|
trigger: "agent"
|
|
@@ -2484,6 +2506,14 @@ function createQueries(table) {
|
|
|
2484
2506
|
const result = await query.first();
|
|
2485
2507
|
return result;
|
|
2486
2508
|
},
|
|
2509
|
+
[`${tableNameSingular}ByIds`]: async (_, args, context, info) => {
|
|
2510
|
+
const { db: db3 } = context;
|
|
2511
|
+
const requestedFields = getRequestedFields(info);
|
|
2512
|
+
let query = db3.from(tableNamePlural).select(requestedFields).whereIn("id", args.ids);
|
|
2513
|
+
query = applyAccessControl(table, context.user, query);
|
|
2514
|
+
const result = await query;
|
|
2515
|
+
return result;
|
|
2516
|
+
},
|
|
2487
2517
|
[`${tableNameSingular}One`]: async (_, args, context, info) => {
|
|
2488
2518
|
const { filters = [], sort } = args;
|
|
2489
2519
|
const { db: db3 } = context;
|
|
@@ -2648,6 +2678,7 @@ function createSDL(tables) {
|
|
|
2648
2678
|
console.log("[EXULU] Adding table >>>>>", tableNamePlural);
|
|
2649
2679
|
typeDefs += `
|
|
2650
2680
|
${tableNameSingular}ById(id: ID!): ${tableNameSingular}
|
|
2681
|
+
${tableNameSingular}ByIds(ids: [ID!]!): [${tableNameSingular}]!
|
|
2651
2682
|
${tableNamePlural}Pagination(limit: Int, page: Int, filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingularUpperCaseFirst}PaginationResult
|
|
2652
2683
|
${tableNameSingular}One(filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingular}
|
|
2653
2684
|
${tableNamePlural}Statistics(filters: [Filter${tableNameSingularUpperCaseFirst}], groupBy: String): [StatisticsResult]!
|
|
@@ -2884,6 +2915,10 @@ var agentsSchema = {
|
|
|
2884
2915
|
name: "name",
|
|
2885
2916
|
type: "text"
|
|
2886
2917
|
},
|
|
2918
|
+
{
|
|
2919
|
+
name: "image",
|
|
2920
|
+
type: "text"
|
|
2921
|
+
},
|
|
2887
2922
|
{
|
|
2888
2923
|
name: "description",
|
|
2889
2924
|
type: "text"
|
|
@@ -2926,6 +2961,10 @@ var usersSchema = {
|
|
|
2926
2961
|
type: "number",
|
|
2927
2962
|
index: true
|
|
2928
2963
|
},
|
|
2964
|
+
{
|
|
2965
|
+
name: "favourite_agents",
|
|
2966
|
+
type: "json"
|
|
2967
|
+
},
|
|
2929
2968
|
{
|
|
2930
2969
|
name: "firstname",
|
|
2931
2970
|
type: "text"
|
|
@@ -3679,6 +3718,9 @@ Intelligence Management Platform
|
|
|
3679
3718
|
};
|
|
3680
3719
|
|
|
3681
3720
|
// src/registry/routes.ts
|
|
3721
|
+
var import_openai = __toESM(require("openai"), 1);
|
|
3722
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
3723
|
+
var import_node_crypto = require("crypto");
|
|
3682
3724
|
var REQUEST_SIZE_LIMIT = "50mb";
|
|
3683
3725
|
var global_queues = {
|
|
3684
3726
|
logs_cleaner: "logs-cleaner"
|
|
@@ -3859,6 +3901,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
3859
3901
|
rights_mode: agent.rights_mode,
|
|
3860
3902
|
slug: backend?.slug,
|
|
3861
3903
|
rateLimit: backend?.rateLimit,
|
|
3904
|
+
image: agent.image,
|
|
3862
3905
|
streaming: backend?.streaming,
|
|
3863
3906
|
capabilities: backend?.capabilities,
|
|
3864
3907
|
RBAC: agent.RBAC,
|
|
@@ -3906,6 +3949,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
3906
3949
|
model: backend?.model?.create({ apiKey: "" }).modelId,
|
|
3907
3950
|
active: agent.active,
|
|
3908
3951
|
public: agent.public,
|
|
3952
|
+
image: agent.image,
|
|
3909
3953
|
type: agent.type,
|
|
3910
3954
|
rights_mode: agent.rights_mode,
|
|
3911
3955
|
slug: backend?.slug,
|
|
@@ -3929,6 +3973,97 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
3929
3973
|
inputSchema: tool2.inputSchema ? (0, import_zodex.zerialize)(tool2.inputSchema) : null
|
|
3930
3974
|
})));
|
|
3931
3975
|
});
|
|
3976
|
+
app.post("/generate/agent/image", async (req, res) => {
|
|
3977
|
+
console.log("[EXULU] generate/agent/image", req.body);
|
|
3978
|
+
const authenticationResult = await requestValidators.authenticate(req);
|
|
3979
|
+
if (!authenticationResult.user?.id) {
|
|
3980
|
+
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
3981
|
+
return;
|
|
3982
|
+
}
|
|
3983
|
+
const { name, description, style } = req.body;
|
|
3984
|
+
if (!name || !description) {
|
|
3985
|
+
res.status(400).json({
|
|
3986
|
+
message: "Missing name or description in request."
|
|
3987
|
+
});
|
|
3988
|
+
return;
|
|
3989
|
+
}
|
|
3990
|
+
const { db: db3 } = await postgresClient();
|
|
3991
|
+
const variable = await db3.from("variables").where({ name: "OPENAI_IMAGE_GENERATION_API_KEY" }).first();
|
|
3992
|
+
if (!variable) {
|
|
3993
|
+
res.status(400).json({
|
|
3994
|
+
message: "Provider API key variable not found."
|
|
3995
|
+
});
|
|
3996
|
+
return;
|
|
3997
|
+
}
|
|
3998
|
+
let providerApiKey = variable.value;
|
|
3999
|
+
if (!variable.encrypted) {
|
|
4000
|
+
res.status(400).json({
|
|
4001
|
+
message: "Provider API key variable not encrypted, for security reasons you are only allowed to use encrypted variables for provider API keys."
|
|
4002
|
+
});
|
|
4003
|
+
return;
|
|
4004
|
+
}
|
|
4005
|
+
if (variable.encrypted) {
|
|
4006
|
+
const bytes = import_crypto_js3.default.AES.decrypt(variable.value, process.env.NEXTAUTH_SECRET);
|
|
4007
|
+
providerApiKey = bytes.toString(import_crypto_js3.default.enc.Utf8);
|
|
4008
|
+
}
|
|
4009
|
+
const openai = new import_openai.default({
|
|
4010
|
+
apiKey: providerApiKey
|
|
4011
|
+
});
|
|
4012
|
+
let style_reference = "";
|
|
4013
|
+
if (style === "origami") {
|
|
4014
|
+
style_reference = "minimalistic origami-style, futuristic robot, portrait, focus on face.";
|
|
4015
|
+
} else if (style === "anime") {
|
|
4016
|
+
style_reference = "minimalistic, make it in the style of a felt puppet, futuristic robot, portrait, focus on face.";
|
|
4017
|
+
} else if (style === "japanese_anime") {
|
|
4018
|
+
style_reference = "minimalistic, make it in the style of japanese anime, futuristic robot, portrait, focus on face.";
|
|
4019
|
+
} else if (style === "vaporwave") {
|
|
4020
|
+
style_reference = "minimalistic, make it in the style of a vaporwave album cover, futuristic robot, portrait, focus on face.";
|
|
4021
|
+
} else if (style === "lego") {
|
|
4022
|
+
style_reference = "minimalistic, make it in the style of LEGO minifigures, futuristic robot, portrait, focus on face.";
|
|
4023
|
+
} else if (style === "paper_cut") {
|
|
4024
|
+
style_reference = "minimalistic, make it in the style of Paper-cut style portrait with color layers, futuristic robot, portrait, focus on face.";
|
|
4025
|
+
} else if (style === "felt_puppet") {
|
|
4026
|
+
style_reference = "minimalistic, make it in the style of a felt puppet, futuristic robot, portrait, focus on face.";
|
|
4027
|
+
} else if (style === "app_icon") {
|
|
4028
|
+
style_reference = "A playful and modern app icon design of a robot, minimal flat vector style, glossy highlights, soft shadows, centered composition, high contrast, vibrant colors, rounded corners, on a transparent background, icon-friendly, no text, no details outside the frame, size is 1024x1024.";
|
|
4029
|
+
} else if (style === "pixel_art") {
|
|
4030
|
+
style_reference = "A pixel art style of a robot, minimal flat vector style, glossy highlights, soft shadows, centered composition, high contrast, vibrant colors, rounded corners, on a transparent background, icon-friendly, no text, no details outside the frame, size is 1024x1024.";
|
|
4031
|
+
} else if (style === "isometric") {
|
|
4032
|
+
style_reference = "3D isometric icon of a robot, centered composition, on a transparent background, no text, no details outside the frame, size is 1024x1024.";
|
|
4033
|
+
} else {
|
|
4034
|
+
style_reference = "A minimalist 3D, robot, portrait, focus on face, floating in space, low-poly design with pastel colors.";
|
|
4035
|
+
}
|
|
4036
|
+
const prompt = `
|
|
4037
|
+
A digital portrait of ${name}, visualized as a futuristic robot.
|
|
4038
|
+
The robot\u2019s design reflects '${description}', with props, tools, or symbolic objects that represent its expertise or area of work.
|
|
4039
|
+
Example: if the agent is a financial analyst, it may hold a stack of papers; if it\u2019s a creative strategist it may be painting on a canvas.
|
|
4040
|
+
Style: ${style_reference}.
|
|
4041
|
+
The portrait should have a clean background.
|
|
4042
|
+
Framing: bust portrait, centered.
|
|
4043
|
+
Mood: friendly and intelligent.
|
|
4044
|
+
`;
|
|
4045
|
+
const result = await openai.images.generate({
|
|
4046
|
+
model: "gpt-image-1",
|
|
4047
|
+
prompt
|
|
4048
|
+
});
|
|
4049
|
+
const image_base64 = result.data?.[0]?.b64_json;
|
|
4050
|
+
if (!image_base64) {
|
|
4051
|
+
res.status(500).json({
|
|
4052
|
+
message: "Failed to generate image."
|
|
4053
|
+
});
|
|
4054
|
+
return;
|
|
4055
|
+
}
|
|
4056
|
+
const image_bytes = Buffer.from(image_base64, "base64");
|
|
4057
|
+
const uuid = (0, import_node_crypto.randomUUID)();
|
|
4058
|
+
if (!import_fs.default.existsSync("public")) {
|
|
4059
|
+
import_fs.default.mkdirSync("public");
|
|
4060
|
+
}
|
|
4061
|
+
import_fs.default.writeFileSync(`public/${uuid}.png`, image_bytes);
|
|
4062
|
+
res.status(200).json({
|
|
4063
|
+
message: "Image generated successfully.",
|
|
4064
|
+
image: `${process.env.BACKEND}/${uuid}.png`
|
|
4065
|
+
});
|
|
4066
|
+
});
|
|
3932
4067
|
app.get("/tools/:id", async (req, res) => {
|
|
3933
4068
|
const id = req.params.id;
|
|
3934
4069
|
if (!id) {
|
|
@@ -4104,7 +4239,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4104
4239
|
if (!exists) {
|
|
4105
4240
|
await context.createItemsTable();
|
|
4106
4241
|
}
|
|
4107
|
-
const result = await context.updateItem(authenticationResult.user.id, req.params.id, req.body);
|
|
4242
|
+
const result = await context.updateItem(authenticationResult.user.id, req.params.id, req.body, authenticationResult.user.role?.id);
|
|
4108
4243
|
res.status(200).json({
|
|
4109
4244
|
message: "Item updated successfully.",
|
|
4110
4245
|
id: result
|
|
@@ -4151,7 +4286,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4151
4286
|
await context.createItemsTable();
|
|
4152
4287
|
}
|
|
4153
4288
|
console.log("[EXULU] inserting item", req.body);
|
|
4154
|
-
const result = await context.insertItem(authenticationResult.user.id, req.body, !!req.body.upsert);
|
|
4289
|
+
const result = await context.insertItem(authenticationResult.user.id, req.body, !!req.body.upsert, authenticationResult.user.role?.id);
|
|
4155
4290
|
console.log("[EXULU] result", result);
|
|
4156
4291
|
res.status(200).json({
|
|
4157
4292
|
message: "Item created successfully.",
|
|
@@ -4212,6 +4347,8 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4212
4347
|
const result = await context.getItems({
|
|
4213
4348
|
sort,
|
|
4214
4349
|
order,
|
|
4350
|
+
user: authenticationResult.user?.id,
|
|
4351
|
+
role: authenticationResult.user?.role?.id,
|
|
4215
4352
|
page,
|
|
4216
4353
|
limit,
|
|
4217
4354
|
archived: req.query.archived === "true",
|
|
@@ -4373,6 +4510,8 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4373
4510
|
const items = await context.getItems({
|
|
4374
4511
|
page: 1,
|
|
4375
4512
|
// todo add pagination
|
|
4513
|
+
user: authenticationResult.user?.id,
|
|
4514
|
+
role: authenticationResult.user?.role?.id,
|
|
4376
4515
|
limit: 500
|
|
4377
4516
|
});
|
|
4378
4517
|
const csv = Papa.unparse(items);
|
|
@@ -4523,7 +4662,8 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4523
4662
|
res,
|
|
4524
4663
|
req
|
|
4525
4664
|
},
|
|
4526
|
-
user:
|
|
4665
|
+
user: user?.id,
|
|
4666
|
+
role: user?.role?.id,
|
|
4527
4667
|
session: headers.session,
|
|
4528
4668
|
message: req.body.message,
|
|
4529
4669
|
tools: enabledTools,
|
|
@@ -4537,8 +4677,9 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4537
4677
|
return;
|
|
4538
4678
|
} else {
|
|
4539
4679
|
const response = await agent.generateSync({
|
|
4540
|
-
user:
|
|
4680
|
+
user: user?.id,
|
|
4541
4681
|
session: headers.session,
|
|
4682
|
+
role: user?.role?.id,
|
|
4542
4683
|
message: req.body.message,
|
|
4543
4684
|
tools: enabledTools.map((tool2) => tool2.tool),
|
|
4544
4685
|
providerApiKey,
|
|
@@ -4637,7 +4778,9 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4637
4778
|
label: "Claude Code",
|
|
4638
4779
|
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
4639
4780
|
trigger: "claude-code",
|
|
4640
|
-
count: 1
|
|
4781
|
+
count: 1,
|
|
4782
|
+
user: authenticationResult.user?.id,
|
|
4783
|
+
role: authenticationResult.user.role?.id
|
|
4641
4784
|
});
|
|
4642
4785
|
response.headers.forEach((value, key) => {
|
|
4643
4786
|
res.setHeader(key, value);
|
|
@@ -4675,6 +4818,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4675
4818
|
}
|
|
4676
4819
|
}
|
|
4677
4820
|
});
|
|
4821
|
+
app.use(import_express4.default.static("public"));
|
|
4678
4822
|
return app;
|
|
4679
4823
|
};
|
|
4680
4824
|
var createCustomAnthropicStreamingMessage = (message) => {
|
|
@@ -4739,7 +4883,7 @@ var bullmq = {
|
|
|
4739
4883
|
};
|
|
4740
4884
|
|
|
4741
4885
|
// src/registry/workers.ts
|
|
4742
|
-
var
|
|
4886
|
+
var fs3 = __toESM(require("fs"), 1);
|
|
4743
4887
|
var import_path = __toESM(require("path"), 1);
|
|
4744
4888
|
var defaultLogsDir = import_path.default.join(process.cwd(), "logs");
|
|
4745
4889
|
var redisConnection;
|
|
@@ -4873,16 +5017,16 @@ var createLogsCleanerWorker = (logsDir) => {
|
|
|
4873
5017
|
global_queues.logs_cleaner,
|
|
4874
5018
|
async (job) => {
|
|
4875
5019
|
console.log(`[EXULU] recurring job ${job.id}.`);
|
|
4876
|
-
const folder =
|
|
5020
|
+
const folder = fs3.readdirSync(logsDir);
|
|
4877
5021
|
const files = folder.filter((file) => file.endsWith(".log"));
|
|
4878
5022
|
const now = /* @__PURE__ */ new Date();
|
|
4879
5023
|
const daysToKeep = job.data.ttld;
|
|
4880
5024
|
const dateToKeep = new Date(now.getTime() - daysToKeep * 24 * 60 * 60 * 1e3);
|
|
4881
5025
|
files.forEach((file) => {
|
|
4882
5026
|
const filePath = import_path.default.join(logsDir, file);
|
|
4883
|
-
const fileStats =
|
|
5027
|
+
const fileStats = fs3.statSync(filePath);
|
|
4884
5028
|
if (fileStats.mtime < dateToKeep) {
|
|
4885
|
-
|
|
5029
|
+
fs3.unlinkSync(filePath);
|
|
4886
5030
|
}
|
|
4887
5031
|
});
|
|
4888
5032
|
},
|
|
@@ -4902,7 +5046,7 @@ var createLogsCleanerWorker = (logsDir) => {
|
|
|
4902
5046
|
|
|
4903
5047
|
// src/mcp/index.ts
|
|
4904
5048
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
4905
|
-
var
|
|
5049
|
+
var import_node_crypto2 = require("crypto");
|
|
4906
5050
|
var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
4907
5051
|
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
4908
5052
|
var import_zod3 = require("zod");
|
|
@@ -4996,7 +5140,7 @@ ${code}`
|
|
|
4996
5140
|
transport = this.transports[sessionId];
|
|
4997
5141
|
} else if (!sessionId && (0, import_types.isInitializeRequest)(req.body)) {
|
|
4998
5142
|
transport = new import_streamableHttp.StreamableHTTPServerTransport({
|
|
4999
|
-
sessionIdGenerator: () => (0,
|
|
5143
|
+
sessionIdGenerator: () => (0, import_node_crypto2.randomUUID)(),
|
|
5000
5144
|
onsessioninitialized: (sessionId2) => {
|
|
5001
5145
|
this.transports[sessionId2] = transport;
|
|
5002
5146
|
}
|
|
@@ -5064,6 +5208,7 @@ var defaultAgent = new ExuluAgent({
|
|
|
5064
5208
|
description: `Basic agent without any defined tools, that can support MCP's.`,
|
|
5065
5209
|
type: "agent",
|
|
5066
5210
|
capabilities: {
|
|
5211
|
+
text: true,
|
|
5067
5212
|
images: [],
|
|
5068
5213
|
files: [],
|
|
5069
5214
|
audio: [],
|
package/dist/index.d.cts
CHANGED
|
@@ -119,6 +119,7 @@ interface ExuluAgentParams {
|
|
|
119
119
|
description: string;
|
|
120
120
|
config?: ExuluAgentConfig | undefined;
|
|
121
121
|
capabilities?: {
|
|
122
|
+
text: boolean;
|
|
122
123
|
images: string[];
|
|
123
124
|
files: string[];
|
|
124
125
|
audio: string[];
|
|
@@ -152,6 +153,7 @@ declare class ExuluAgent {
|
|
|
152
153
|
}) => LanguageModel;
|
|
153
154
|
};
|
|
154
155
|
capabilities: {
|
|
156
|
+
text: boolean;
|
|
155
157
|
images: string[];
|
|
156
158
|
files: string[];
|
|
157
159
|
audio: string[];
|
|
@@ -161,9 +163,10 @@ declare class ExuluAgent {
|
|
|
161
163
|
get providerName(): string;
|
|
162
164
|
get modelName(): string;
|
|
163
165
|
tool: () => ExuluTool;
|
|
164
|
-
generateSync: ({ prompt, user, session, message, tools, statistics, toolConfigs, providerApiKey }: {
|
|
166
|
+
generateSync: ({ prompt, user, role, session, message, tools, statistics, toolConfigs, providerApiKey }: {
|
|
165
167
|
prompt?: string;
|
|
166
168
|
user?: string;
|
|
169
|
+
role?: string;
|
|
167
170
|
session?: string;
|
|
168
171
|
message?: UIMessage;
|
|
169
172
|
tools?: ExuluTool[];
|
|
@@ -171,12 +174,13 @@ declare class ExuluAgent {
|
|
|
171
174
|
toolConfigs?: ExuluAgentToolConfig[];
|
|
172
175
|
providerApiKey: string;
|
|
173
176
|
}) => Promise<string>;
|
|
174
|
-
generateStream: ({ express, user, session, message, tools, statistics, toolConfigs, providerApiKey }: {
|
|
177
|
+
generateStream: ({ express, user, role, session, message, tools, statistics, toolConfigs, providerApiKey }: {
|
|
175
178
|
express: {
|
|
176
179
|
res: Response;
|
|
177
180
|
req: Request;
|
|
178
181
|
};
|
|
179
182
|
user: string;
|
|
183
|
+
role: string;
|
|
180
184
|
session: string;
|
|
181
185
|
message?: UIMessage;
|
|
182
186
|
tools?: ExuluTool[];
|
|
@@ -230,8 +234,8 @@ declare class ExuluEmbedder {
|
|
|
230
234
|
vectorDimensions: number;
|
|
231
235
|
maxChunkSize: number;
|
|
232
236
|
});
|
|
233
|
-
generateFromQuery(query: string, statistics?: ExuluStatisticParams): VectorGenerationResponse;
|
|
234
|
-
generateFromDocument(input: Item, statistics?: ExuluStatisticParams): VectorGenerationResponse;
|
|
237
|
+
generateFromQuery(query: string, statistics?: ExuluStatisticParams, user?: string, role?: string): VectorGenerationResponse;
|
|
238
|
+
generateFromDocument(input: Item, statistics?: ExuluStatisticParams, user?: string, role?: string): VectorGenerationResponse;
|
|
235
239
|
}
|
|
236
240
|
declare class ExuluLogger {
|
|
237
241
|
private readonly logPath?;
|
|
@@ -384,21 +388,23 @@ declare class ExuluContext {
|
|
|
384
388
|
getTableName: () => string;
|
|
385
389
|
getChunksTableName: () => string;
|
|
386
390
|
tableExists: () => Promise<boolean>;
|
|
387
|
-
updateItem(user: string, id: string, item: Item): Promise<{
|
|
391
|
+
updateItem(user: string, id: string, item: Item, role?: string): Promise<{
|
|
388
392
|
id: string;
|
|
389
393
|
job?: string;
|
|
390
394
|
}>;
|
|
391
|
-
insertItem(user: string, item: Item, upsert?: boolean): Promise<{
|
|
395
|
+
insertItem(user: string, item: Item, upsert?: boolean, role?: string): Promise<{
|
|
392
396
|
id: string;
|
|
393
397
|
job?: string;
|
|
394
398
|
}>;
|
|
395
|
-
getItems: ({ statistics, limit, sort, order, page, name, archived, query, method }: {
|
|
399
|
+
getItems: ({ statistics, limit, sort, order, page, name, user, role, archived, query, method }: {
|
|
396
400
|
statistics?: ExuluStatisticParams;
|
|
397
401
|
page: number;
|
|
398
402
|
sort?: "created_at" | "embeddings_updated_at";
|
|
399
403
|
order?: "desc" | "asc";
|
|
400
404
|
limit: number;
|
|
401
405
|
name?: string;
|
|
406
|
+
user?: string;
|
|
407
|
+
role?: string;
|
|
402
408
|
archived?: boolean;
|
|
403
409
|
query?: string;
|
|
404
410
|
method?: VectorMethod;
|
|
@@ -479,11 +485,12 @@ type ExuluSourceUpdaterArgs = {
|
|
|
479
485
|
example: string;
|
|
480
486
|
}>;
|
|
481
487
|
};
|
|
488
|
+
type STATISTICS_LABELS = "tool" | "agent" | "flow" | "api" | "claude-code";
|
|
482
489
|
type ExuluStatistic = {
|
|
483
490
|
name: string;
|
|
484
491
|
label: string;
|
|
485
492
|
type: STATISTICS_TYPE;
|
|
486
|
-
trigger:
|
|
493
|
+
trigger: STATISTICS_LABELS;
|
|
487
494
|
total: number;
|
|
488
495
|
};
|
|
489
496
|
type ExuluStatisticParams = Omit<ExuluStatistic, "total" | "name" | "type">;
|
|
@@ -544,6 +551,7 @@ type User = {
|
|
|
544
551
|
type?: "api" | "user";
|
|
545
552
|
anthropic_token?: string;
|
|
546
553
|
super_admin?: boolean;
|
|
554
|
+
favourite_agents?: string[];
|
|
547
555
|
role: {
|
|
548
556
|
id: string;
|
|
549
557
|
name: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -119,6 +119,7 @@ interface ExuluAgentParams {
|
|
|
119
119
|
description: string;
|
|
120
120
|
config?: ExuluAgentConfig | undefined;
|
|
121
121
|
capabilities?: {
|
|
122
|
+
text: boolean;
|
|
122
123
|
images: string[];
|
|
123
124
|
files: string[];
|
|
124
125
|
audio: string[];
|
|
@@ -152,6 +153,7 @@ declare class ExuluAgent {
|
|
|
152
153
|
}) => LanguageModel;
|
|
153
154
|
};
|
|
154
155
|
capabilities: {
|
|
156
|
+
text: boolean;
|
|
155
157
|
images: string[];
|
|
156
158
|
files: string[];
|
|
157
159
|
audio: string[];
|
|
@@ -161,9 +163,10 @@ declare class ExuluAgent {
|
|
|
161
163
|
get providerName(): string;
|
|
162
164
|
get modelName(): string;
|
|
163
165
|
tool: () => ExuluTool;
|
|
164
|
-
generateSync: ({ prompt, user, session, message, tools, statistics, toolConfigs, providerApiKey }: {
|
|
166
|
+
generateSync: ({ prompt, user, role, session, message, tools, statistics, toolConfigs, providerApiKey }: {
|
|
165
167
|
prompt?: string;
|
|
166
168
|
user?: string;
|
|
169
|
+
role?: string;
|
|
167
170
|
session?: string;
|
|
168
171
|
message?: UIMessage;
|
|
169
172
|
tools?: ExuluTool[];
|
|
@@ -171,12 +174,13 @@ declare class ExuluAgent {
|
|
|
171
174
|
toolConfigs?: ExuluAgentToolConfig[];
|
|
172
175
|
providerApiKey: string;
|
|
173
176
|
}) => Promise<string>;
|
|
174
|
-
generateStream: ({ express, user, session, message, tools, statistics, toolConfigs, providerApiKey }: {
|
|
177
|
+
generateStream: ({ express, user, role, session, message, tools, statistics, toolConfigs, providerApiKey }: {
|
|
175
178
|
express: {
|
|
176
179
|
res: Response;
|
|
177
180
|
req: Request;
|
|
178
181
|
};
|
|
179
182
|
user: string;
|
|
183
|
+
role: string;
|
|
180
184
|
session: string;
|
|
181
185
|
message?: UIMessage;
|
|
182
186
|
tools?: ExuluTool[];
|
|
@@ -230,8 +234,8 @@ declare class ExuluEmbedder {
|
|
|
230
234
|
vectorDimensions: number;
|
|
231
235
|
maxChunkSize: number;
|
|
232
236
|
});
|
|
233
|
-
generateFromQuery(query: string, statistics?: ExuluStatisticParams): VectorGenerationResponse;
|
|
234
|
-
generateFromDocument(input: Item, statistics?: ExuluStatisticParams): VectorGenerationResponse;
|
|
237
|
+
generateFromQuery(query: string, statistics?: ExuluStatisticParams, user?: string, role?: string): VectorGenerationResponse;
|
|
238
|
+
generateFromDocument(input: Item, statistics?: ExuluStatisticParams, user?: string, role?: string): VectorGenerationResponse;
|
|
235
239
|
}
|
|
236
240
|
declare class ExuluLogger {
|
|
237
241
|
private readonly logPath?;
|
|
@@ -384,21 +388,23 @@ declare class ExuluContext {
|
|
|
384
388
|
getTableName: () => string;
|
|
385
389
|
getChunksTableName: () => string;
|
|
386
390
|
tableExists: () => Promise<boolean>;
|
|
387
|
-
updateItem(user: string, id: string, item: Item): Promise<{
|
|
391
|
+
updateItem(user: string, id: string, item: Item, role?: string): Promise<{
|
|
388
392
|
id: string;
|
|
389
393
|
job?: string;
|
|
390
394
|
}>;
|
|
391
|
-
insertItem(user: string, item: Item, upsert?: boolean): Promise<{
|
|
395
|
+
insertItem(user: string, item: Item, upsert?: boolean, role?: string): Promise<{
|
|
392
396
|
id: string;
|
|
393
397
|
job?: string;
|
|
394
398
|
}>;
|
|
395
|
-
getItems: ({ statistics, limit, sort, order, page, name, archived, query, method }: {
|
|
399
|
+
getItems: ({ statistics, limit, sort, order, page, name, user, role, archived, query, method }: {
|
|
396
400
|
statistics?: ExuluStatisticParams;
|
|
397
401
|
page: number;
|
|
398
402
|
sort?: "created_at" | "embeddings_updated_at";
|
|
399
403
|
order?: "desc" | "asc";
|
|
400
404
|
limit: number;
|
|
401
405
|
name?: string;
|
|
406
|
+
user?: string;
|
|
407
|
+
role?: string;
|
|
402
408
|
archived?: boolean;
|
|
403
409
|
query?: string;
|
|
404
410
|
method?: VectorMethod;
|
|
@@ -479,11 +485,12 @@ type ExuluSourceUpdaterArgs = {
|
|
|
479
485
|
example: string;
|
|
480
486
|
}>;
|
|
481
487
|
};
|
|
488
|
+
type STATISTICS_LABELS = "tool" | "agent" | "flow" | "api" | "claude-code";
|
|
482
489
|
type ExuluStatistic = {
|
|
483
490
|
name: string;
|
|
484
491
|
label: string;
|
|
485
492
|
type: STATISTICS_TYPE;
|
|
486
|
-
trigger:
|
|
493
|
+
trigger: STATISTICS_LABELS;
|
|
487
494
|
total: number;
|
|
488
495
|
};
|
|
489
496
|
type ExuluStatisticParams = Omit<ExuluStatistic, "total" | "name" | "type">;
|
|
@@ -544,6 +551,7 @@ type User = {
|
|
|
544
551
|
type?: "api" | "user";
|
|
545
552
|
anthropic_token?: string;
|
|
546
553
|
super_admin?: boolean;
|
|
554
|
+
favourite_agents?: string[];
|
|
547
555
|
role: {
|
|
548
556
|
id: string;
|
|
549
557
|
name: string;
|
package/dist/index.js
CHANGED
|
@@ -436,7 +436,7 @@ function sanitizeToolName(name) {
|
|
|
436
436
|
}
|
|
437
437
|
return sanitized;
|
|
438
438
|
}
|
|
439
|
-
var convertToolsArrayToObject = (tools, configs, providerApiKey) => {
|
|
439
|
+
var convertToolsArrayToObject = (tools, configs, providerApiKey, user, role) => {
|
|
440
440
|
if (!tools) return {};
|
|
441
441
|
const sanitizedTools = tools ? tools.map((tool2) => ({
|
|
442
442
|
...tool2,
|
|
@@ -471,6 +471,8 @@ var convertToolsArrayToObject = (tools, configs, providerApiKey) => {
|
|
|
471
471
|
// is available, after we added the .value property
|
|
472
472
|
// by hydrating it from the variables table.
|
|
473
473
|
providerApiKey,
|
|
474
|
+
user,
|
|
475
|
+
role,
|
|
474
476
|
config: config ? config.config.reduce((acc, curr) => {
|
|
475
477
|
acc[curr.name] = curr.value;
|
|
476
478
|
return acc;
|
|
@@ -547,6 +549,7 @@ var ExuluAgent = class {
|
|
|
547
549
|
this.config = config;
|
|
548
550
|
this.type = type;
|
|
549
551
|
this.capabilities = capabilities || {
|
|
552
|
+
text: false,
|
|
550
553
|
images: [],
|
|
551
554
|
files: [],
|
|
552
555
|
audio: [],
|
|
@@ -575,10 +578,12 @@ var ExuluAgent = class {
|
|
|
575
578
|
}),
|
|
576
579
|
description: `A function that calls an AI agent named: ${this.name}. The agent does the following: ${this.description}.`,
|
|
577
580
|
config: [],
|
|
578
|
-
execute: async ({ prompt, config, providerApiKey }) => {
|
|
581
|
+
execute: async ({ prompt, config, providerApiKey, user, role }) => {
|
|
579
582
|
return await this.generateSync({
|
|
580
583
|
prompt,
|
|
581
584
|
providerApiKey,
|
|
585
|
+
user,
|
|
586
|
+
role,
|
|
582
587
|
statistics: {
|
|
583
588
|
label: "",
|
|
584
589
|
trigger: "tool"
|
|
@@ -587,7 +592,7 @@ var ExuluAgent = class {
|
|
|
587
592
|
}
|
|
588
593
|
});
|
|
589
594
|
};
|
|
590
|
-
generateSync = async ({ prompt, user, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
595
|
+
generateSync = async ({ prompt, user, role, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
591
596
|
if (!this.model) {
|
|
592
597
|
throw new Error("Model is required for streaming.");
|
|
593
598
|
}
|
|
@@ -623,7 +628,7 @@ var ExuluAgent = class {
|
|
|
623
628
|
messages: messages ? convertToModelMessages(messages) : void 0,
|
|
624
629
|
prompt,
|
|
625
630
|
maxRetries: 2,
|
|
626
|
-
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey),
|
|
631
|
+
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey, user, role),
|
|
627
632
|
stopWhen: [stepCountIs(5)]
|
|
628
633
|
});
|
|
629
634
|
if (statistics) {
|
|
@@ -632,12 +637,14 @@ var ExuluAgent = class {
|
|
|
632
637
|
label: statistics.label,
|
|
633
638
|
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
634
639
|
trigger: statistics.trigger,
|
|
635
|
-
count: 1
|
|
640
|
+
count: 1,
|
|
641
|
+
user,
|
|
642
|
+
role
|
|
636
643
|
});
|
|
637
644
|
}
|
|
638
645
|
return text;
|
|
639
646
|
};
|
|
640
|
-
generateStream = async ({ express: express3, user, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
647
|
+
generateStream = async ({ express: express3, user, role, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
641
648
|
if (!this.model) {
|
|
642
649
|
throw new Error("Model is required for streaming.");
|
|
643
650
|
}
|
|
@@ -670,7 +677,7 @@ var ExuluAgent = class {
|
|
|
670
677
|
messages: messages ? convertToModelMessages(messages) : void 0,
|
|
671
678
|
system: "You are a helpful assistant. When you use a tool to answer a question do not explicitly comment on the result of the tool call unless the user has explicitly you to do something with the result.",
|
|
672
679
|
maxRetries: 2,
|
|
673
|
-
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey),
|
|
680
|
+
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey, user, role),
|
|
674
681
|
onError: (error) => console.error("[EXULU] chat stream error.", error),
|
|
675
682
|
stopWhen: [stepCountIs(5)]
|
|
676
683
|
});
|
|
@@ -698,7 +705,9 @@ var ExuluAgent = class {
|
|
|
698
705
|
label: statistics.label,
|
|
699
706
|
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
700
707
|
trigger: statistics.trigger,
|
|
701
|
-
count: 1
|
|
708
|
+
count: 1,
|
|
709
|
+
user,
|
|
710
|
+
role
|
|
702
711
|
});
|
|
703
712
|
}
|
|
704
713
|
}
|
|
@@ -742,14 +751,16 @@ var ExuluEmbedder = class {
|
|
|
742
751
|
this.queue = queue;
|
|
743
752
|
this.generateEmbeddings = generateEmbeddings;
|
|
744
753
|
}
|
|
745
|
-
async generateFromQuery(query, statistics) {
|
|
754
|
+
async generateFromQuery(query, statistics, user, role) {
|
|
746
755
|
if (statistics) {
|
|
747
756
|
await updateStatistic({
|
|
748
757
|
name: "count",
|
|
749
758
|
label: statistics.label,
|
|
750
759
|
type: STATISTICS_TYPE_ENUM.EMBEDDER_GENERATE,
|
|
751
760
|
trigger: statistics.trigger,
|
|
752
|
-
count: 1
|
|
761
|
+
count: 1,
|
|
762
|
+
user,
|
|
763
|
+
role
|
|
753
764
|
});
|
|
754
765
|
}
|
|
755
766
|
return await this.generateEmbeddings({
|
|
@@ -762,14 +773,16 @@ var ExuluEmbedder = class {
|
|
|
762
773
|
}]
|
|
763
774
|
});
|
|
764
775
|
}
|
|
765
|
-
async generateFromDocument(input, statistics) {
|
|
776
|
+
async generateFromDocument(input, statistics, user, role) {
|
|
766
777
|
if (statistics) {
|
|
767
778
|
await updateStatistic({
|
|
768
779
|
name: "count",
|
|
769
780
|
label: statistics.label,
|
|
770
781
|
type: STATISTICS_TYPE_ENUM.EMBEDDER_GENERATE,
|
|
771
782
|
trigger: statistics.trigger,
|
|
772
|
-
count: 1
|
|
783
|
+
count: 1,
|
|
784
|
+
user,
|
|
785
|
+
role
|
|
773
786
|
});
|
|
774
787
|
}
|
|
775
788
|
if (!this.chunker) {
|
|
@@ -1023,7 +1036,7 @@ var ExuluContext = class {
|
|
|
1023
1036
|
const tableExists = await db3.schema.hasTable(this.getTableName());
|
|
1024
1037
|
return tableExists;
|
|
1025
1038
|
};
|
|
1026
|
-
async updateItem(user, id, item) {
|
|
1039
|
+
async updateItem(user, id, item, role) {
|
|
1027
1040
|
if (!id) {
|
|
1028
1041
|
throw new Error("Id is required for updating an item.");
|
|
1029
1042
|
}
|
|
@@ -1064,7 +1077,7 @@ var ExuluContext = class {
|
|
|
1064
1077
|
}, {
|
|
1065
1078
|
label: this.name,
|
|
1066
1079
|
trigger: "agent"
|
|
1067
|
-
});
|
|
1080
|
+
}, user, role);
|
|
1068
1081
|
const exists = await db3.schema.hasTable(this.getChunksTableName());
|
|
1069
1082
|
if (!exists) {
|
|
1070
1083
|
await this.createChunksTable();
|
|
@@ -1085,7 +1098,7 @@ var ExuluContext = class {
|
|
|
1085
1098
|
job: void 0
|
|
1086
1099
|
};
|
|
1087
1100
|
}
|
|
1088
|
-
async insertItem(user, item, upsert = false) {
|
|
1101
|
+
async insertItem(user, item, upsert = false, role) {
|
|
1089
1102
|
if (!item.name) {
|
|
1090
1103
|
throw new Error("Name field is required.");
|
|
1091
1104
|
}
|
|
@@ -1096,14 +1109,14 @@ var ExuluContext = class {
|
|
|
1096
1109
|
throw new Error("Item with external id " + item.external_id + " already exists.");
|
|
1097
1110
|
}
|
|
1098
1111
|
if (existingItem && upsert) {
|
|
1099
|
-
await this.updateItem(user, existingItem.id, item);
|
|
1112
|
+
await this.updateItem(user, existingItem.id, item, role);
|
|
1100
1113
|
return existingItem.id;
|
|
1101
1114
|
}
|
|
1102
1115
|
}
|
|
1103
1116
|
if (upsert && item.id) {
|
|
1104
1117
|
const existingItem = await db3.from(this.getTableName()).where({ id: item.id }).first();
|
|
1105
1118
|
if (existingItem && upsert) {
|
|
1106
|
-
await this.updateItem(user, existingItem.id, item);
|
|
1119
|
+
await this.updateItem(user, existingItem.id, item, role);
|
|
1107
1120
|
return existingItem.id;
|
|
1108
1121
|
}
|
|
1109
1122
|
}
|
|
@@ -1147,7 +1160,7 @@ var ExuluContext = class {
|
|
|
1147
1160
|
}, {
|
|
1148
1161
|
label: this.name,
|
|
1149
1162
|
trigger: "agent"
|
|
1150
|
-
});
|
|
1163
|
+
}, user, role);
|
|
1151
1164
|
const exists = await db3.schema.hasTable(this.getChunksTableName());
|
|
1152
1165
|
if (!exists) {
|
|
1153
1166
|
await this.createChunksTable();
|
|
@@ -1175,6 +1188,8 @@ var ExuluContext = class {
|
|
|
1175
1188
|
order,
|
|
1176
1189
|
page,
|
|
1177
1190
|
name,
|
|
1191
|
+
user,
|
|
1192
|
+
role,
|
|
1178
1193
|
archived,
|
|
1179
1194
|
query,
|
|
1180
1195
|
method
|
|
@@ -1243,7 +1258,9 @@ var ExuluContext = class {
|
|
|
1243
1258
|
name: "count",
|
|
1244
1259
|
label: statistics.label,
|
|
1245
1260
|
type: STATISTICS_TYPE_ENUM.CONTEXT_RETRIEVE,
|
|
1246
|
-
trigger: statistics.trigger
|
|
1261
|
+
trigger: statistics.trigger,
|
|
1262
|
+
user,
|
|
1263
|
+
role
|
|
1247
1264
|
});
|
|
1248
1265
|
}
|
|
1249
1266
|
if (this.queryRewriter) {
|
|
@@ -1259,7 +1276,10 @@ var ExuluContext = class {
|
|
|
1259
1276
|
itemsQuery.select(chunksTable + ".chunk_index");
|
|
1260
1277
|
itemsQuery.select(chunksTable + ".created_at as chunk_created_at");
|
|
1261
1278
|
itemsQuery.select(chunksTable + ".updated_at as chunk_updated_at");
|
|
1262
|
-
const { chunks } = await this.embedder.generateFromQuery(query
|
|
1279
|
+
const { chunks } = await this.embedder.generateFromQuery(query, {
|
|
1280
|
+
label: this.name,
|
|
1281
|
+
trigger: "agent"
|
|
1282
|
+
}, user, role);
|
|
1263
1283
|
if (!chunks?.[0]?.vector) {
|
|
1264
1284
|
throw new Error("No vector generated for query.");
|
|
1265
1285
|
}
|
|
@@ -1407,11 +1427,13 @@ var ExuluContext = class {
|
|
|
1407
1427
|
}),
|
|
1408
1428
|
config: [],
|
|
1409
1429
|
description: `Gets information from the context called: ${this.name}. The context description is: ${this.description}.`,
|
|
1410
|
-
execute: async ({ query }) => {
|
|
1430
|
+
execute: async ({ query, user, role }) => {
|
|
1411
1431
|
return await this.getItems({
|
|
1412
1432
|
page: 1,
|
|
1413
1433
|
limit: 10,
|
|
1414
1434
|
query,
|
|
1435
|
+
user,
|
|
1436
|
+
role,
|
|
1415
1437
|
statistics: {
|
|
1416
1438
|
label: this.name,
|
|
1417
1439
|
trigger: "agent"
|
|
@@ -2442,6 +2464,14 @@ function createQueries(table) {
|
|
|
2442
2464
|
const result = await query.first();
|
|
2443
2465
|
return result;
|
|
2444
2466
|
},
|
|
2467
|
+
[`${tableNameSingular}ByIds`]: async (_, args, context, info) => {
|
|
2468
|
+
const { db: db3 } = context;
|
|
2469
|
+
const requestedFields = getRequestedFields(info);
|
|
2470
|
+
let query = db3.from(tableNamePlural).select(requestedFields).whereIn("id", args.ids);
|
|
2471
|
+
query = applyAccessControl(table, context.user, query);
|
|
2472
|
+
const result = await query;
|
|
2473
|
+
return result;
|
|
2474
|
+
},
|
|
2445
2475
|
[`${tableNameSingular}One`]: async (_, args, context, info) => {
|
|
2446
2476
|
const { filters = [], sort } = args;
|
|
2447
2477
|
const { db: db3 } = context;
|
|
@@ -2606,6 +2636,7 @@ function createSDL(tables) {
|
|
|
2606
2636
|
console.log("[EXULU] Adding table >>>>>", tableNamePlural);
|
|
2607
2637
|
typeDefs += `
|
|
2608
2638
|
${tableNameSingular}ById(id: ID!): ${tableNameSingular}
|
|
2639
|
+
${tableNameSingular}ByIds(ids: [ID!]!): [${tableNameSingular}]!
|
|
2609
2640
|
${tableNamePlural}Pagination(limit: Int, page: Int, filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingularUpperCaseFirst}PaginationResult
|
|
2610
2641
|
${tableNameSingular}One(filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingular}
|
|
2611
2642
|
${tableNamePlural}Statistics(filters: [Filter${tableNameSingularUpperCaseFirst}], groupBy: String): [StatisticsResult]!
|
|
@@ -2842,6 +2873,10 @@ var agentsSchema = {
|
|
|
2842
2873
|
name: "name",
|
|
2843
2874
|
type: "text"
|
|
2844
2875
|
},
|
|
2876
|
+
{
|
|
2877
|
+
name: "image",
|
|
2878
|
+
type: "text"
|
|
2879
|
+
},
|
|
2845
2880
|
{
|
|
2846
2881
|
name: "description",
|
|
2847
2882
|
type: "text"
|
|
@@ -2884,6 +2919,10 @@ var usersSchema = {
|
|
|
2884
2919
|
type: "number",
|
|
2885
2920
|
index: true
|
|
2886
2921
|
},
|
|
2922
|
+
{
|
|
2923
|
+
name: "favourite_agents",
|
|
2924
|
+
type: "json"
|
|
2925
|
+
},
|
|
2887
2926
|
{
|
|
2888
2927
|
name: "firstname",
|
|
2889
2928
|
type: "text"
|
|
@@ -3637,6 +3676,9 @@ Intelligence Management Platform
|
|
|
3637
3676
|
};
|
|
3638
3677
|
|
|
3639
3678
|
// src/registry/routes.ts
|
|
3679
|
+
import OpenAI from "openai";
|
|
3680
|
+
import fs2 from "fs";
|
|
3681
|
+
import { randomUUID } from "crypto";
|
|
3640
3682
|
var REQUEST_SIZE_LIMIT = "50mb";
|
|
3641
3683
|
var global_queues = {
|
|
3642
3684
|
logs_cleaner: "logs-cleaner"
|
|
@@ -3817,6 +3859,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
3817
3859
|
rights_mode: agent.rights_mode,
|
|
3818
3860
|
slug: backend?.slug,
|
|
3819
3861
|
rateLimit: backend?.rateLimit,
|
|
3862
|
+
image: agent.image,
|
|
3820
3863
|
streaming: backend?.streaming,
|
|
3821
3864
|
capabilities: backend?.capabilities,
|
|
3822
3865
|
RBAC: agent.RBAC,
|
|
@@ -3864,6 +3907,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
3864
3907
|
model: backend?.model?.create({ apiKey: "" }).modelId,
|
|
3865
3908
|
active: agent.active,
|
|
3866
3909
|
public: agent.public,
|
|
3910
|
+
image: agent.image,
|
|
3867
3911
|
type: agent.type,
|
|
3868
3912
|
rights_mode: agent.rights_mode,
|
|
3869
3913
|
slug: backend?.slug,
|
|
@@ -3887,6 +3931,97 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
3887
3931
|
inputSchema: tool2.inputSchema ? zerialize(tool2.inputSchema) : null
|
|
3888
3932
|
})));
|
|
3889
3933
|
});
|
|
3934
|
+
app.post("/generate/agent/image", async (req, res) => {
|
|
3935
|
+
console.log("[EXULU] generate/agent/image", req.body);
|
|
3936
|
+
const authenticationResult = await requestValidators.authenticate(req);
|
|
3937
|
+
if (!authenticationResult.user?.id) {
|
|
3938
|
+
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
3939
|
+
return;
|
|
3940
|
+
}
|
|
3941
|
+
const { name, description, style } = req.body;
|
|
3942
|
+
if (!name || !description) {
|
|
3943
|
+
res.status(400).json({
|
|
3944
|
+
message: "Missing name or description in request."
|
|
3945
|
+
});
|
|
3946
|
+
return;
|
|
3947
|
+
}
|
|
3948
|
+
const { db: db3 } = await postgresClient();
|
|
3949
|
+
const variable = await db3.from("variables").where({ name: "OPENAI_IMAGE_GENERATION_API_KEY" }).first();
|
|
3950
|
+
if (!variable) {
|
|
3951
|
+
res.status(400).json({
|
|
3952
|
+
message: "Provider API key variable not found."
|
|
3953
|
+
});
|
|
3954
|
+
return;
|
|
3955
|
+
}
|
|
3956
|
+
let providerApiKey = variable.value;
|
|
3957
|
+
if (!variable.encrypted) {
|
|
3958
|
+
res.status(400).json({
|
|
3959
|
+
message: "Provider API key variable not encrypted, for security reasons you are only allowed to use encrypted variables for provider API keys."
|
|
3960
|
+
});
|
|
3961
|
+
return;
|
|
3962
|
+
}
|
|
3963
|
+
if (variable.encrypted) {
|
|
3964
|
+
const bytes = CryptoJS3.AES.decrypt(variable.value, process.env.NEXTAUTH_SECRET);
|
|
3965
|
+
providerApiKey = bytes.toString(CryptoJS3.enc.Utf8);
|
|
3966
|
+
}
|
|
3967
|
+
const openai = new OpenAI({
|
|
3968
|
+
apiKey: providerApiKey
|
|
3969
|
+
});
|
|
3970
|
+
let style_reference = "";
|
|
3971
|
+
if (style === "origami") {
|
|
3972
|
+
style_reference = "minimalistic origami-style, futuristic robot, portrait, focus on face.";
|
|
3973
|
+
} else if (style === "anime") {
|
|
3974
|
+
style_reference = "minimalistic, make it in the style of a felt puppet, futuristic robot, portrait, focus on face.";
|
|
3975
|
+
} else if (style === "japanese_anime") {
|
|
3976
|
+
style_reference = "minimalistic, make it in the style of japanese anime, futuristic robot, portrait, focus on face.";
|
|
3977
|
+
} else if (style === "vaporwave") {
|
|
3978
|
+
style_reference = "minimalistic, make it in the style of a vaporwave album cover, futuristic robot, portrait, focus on face.";
|
|
3979
|
+
} else if (style === "lego") {
|
|
3980
|
+
style_reference = "minimalistic, make it in the style of LEGO minifigures, futuristic robot, portrait, focus on face.";
|
|
3981
|
+
} else if (style === "paper_cut") {
|
|
3982
|
+
style_reference = "minimalistic, make it in the style of Paper-cut style portrait with color layers, futuristic robot, portrait, focus on face.";
|
|
3983
|
+
} else if (style === "felt_puppet") {
|
|
3984
|
+
style_reference = "minimalistic, make it in the style of a felt puppet, futuristic robot, portrait, focus on face.";
|
|
3985
|
+
} else if (style === "app_icon") {
|
|
3986
|
+
style_reference = "A playful and modern app icon design of a robot, minimal flat vector style, glossy highlights, soft shadows, centered composition, high contrast, vibrant colors, rounded corners, on a transparent background, icon-friendly, no text, no details outside the frame, size is 1024x1024.";
|
|
3987
|
+
} else if (style === "pixel_art") {
|
|
3988
|
+
style_reference = "A pixel art style of a robot, minimal flat vector style, glossy highlights, soft shadows, centered composition, high contrast, vibrant colors, rounded corners, on a transparent background, icon-friendly, no text, no details outside the frame, size is 1024x1024.";
|
|
3989
|
+
} else if (style === "isometric") {
|
|
3990
|
+
style_reference = "3D isometric icon of a robot, centered composition, on a transparent background, no text, no details outside the frame, size is 1024x1024.";
|
|
3991
|
+
} else {
|
|
3992
|
+
style_reference = "A minimalist 3D, robot, portrait, focus on face, floating in space, low-poly design with pastel colors.";
|
|
3993
|
+
}
|
|
3994
|
+
const prompt = `
|
|
3995
|
+
A digital portrait of ${name}, visualized as a futuristic robot.
|
|
3996
|
+
The robot\u2019s design reflects '${description}', with props, tools, or symbolic objects that represent its expertise or area of work.
|
|
3997
|
+
Example: if the agent is a financial analyst, it may hold a stack of papers; if it\u2019s a creative strategist it may be painting on a canvas.
|
|
3998
|
+
Style: ${style_reference}.
|
|
3999
|
+
The portrait should have a clean background.
|
|
4000
|
+
Framing: bust portrait, centered.
|
|
4001
|
+
Mood: friendly and intelligent.
|
|
4002
|
+
`;
|
|
4003
|
+
const result = await openai.images.generate({
|
|
4004
|
+
model: "gpt-image-1",
|
|
4005
|
+
prompt
|
|
4006
|
+
});
|
|
4007
|
+
const image_base64 = result.data?.[0]?.b64_json;
|
|
4008
|
+
if (!image_base64) {
|
|
4009
|
+
res.status(500).json({
|
|
4010
|
+
message: "Failed to generate image."
|
|
4011
|
+
});
|
|
4012
|
+
return;
|
|
4013
|
+
}
|
|
4014
|
+
const image_bytes = Buffer.from(image_base64, "base64");
|
|
4015
|
+
const uuid = randomUUID();
|
|
4016
|
+
if (!fs2.existsSync("public")) {
|
|
4017
|
+
fs2.mkdirSync("public");
|
|
4018
|
+
}
|
|
4019
|
+
fs2.writeFileSync(`public/${uuid}.png`, image_bytes);
|
|
4020
|
+
res.status(200).json({
|
|
4021
|
+
message: "Image generated successfully.",
|
|
4022
|
+
image: `${process.env.BACKEND}/${uuid}.png`
|
|
4023
|
+
});
|
|
4024
|
+
});
|
|
3890
4025
|
app.get("/tools/:id", async (req, res) => {
|
|
3891
4026
|
const id = req.params.id;
|
|
3892
4027
|
if (!id) {
|
|
@@ -4062,7 +4197,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4062
4197
|
if (!exists) {
|
|
4063
4198
|
await context.createItemsTable();
|
|
4064
4199
|
}
|
|
4065
|
-
const result = await context.updateItem(authenticationResult.user.id, req.params.id, req.body);
|
|
4200
|
+
const result = await context.updateItem(authenticationResult.user.id, req.params.id, req.body, authenticationResult.user.role?.id);
|
|
4066
4201
|
res.status(200).json({
|
|
4067
4202
|
message: "Item updated successfully.",
|
|
4068
4203
|
id: result
|
|
@@ -4109,7 +4244,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4109
4244
|
await context.createItemsTable();
|
|
4110
4245
|
}
|
|
4111
4246
|
console.log("[EXULU] inserting item", req.body);
|
|
4112
|
-
const result = await context.insertItem(authenticationResult.user.id, req.body, !!req.body.upsert);
|
|
4247
|
+
const result = await context.insertItem(authenticationResult.user.id, req.body, !!req.body.upsert, authenticationResult.user.role?.id);
|
|
4113
4248
|
console.log("[EXULU] result", result);
|
|
4114
4249
|
res.status(200).json({
|
|
4115
4250
|
message: "Item created successfully.",
|
|
@@ -4170,6 +4305,8 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4170
4305
|
const result = await context.getItems({
|
|
4171
4306
|
sort,
|
|
4172
4307
|
order,
|
|
4308
|
+
user: authenticationResult.user?.id,
|
|
4309
|
+
role: authenticationResult.user?.role?.id,
|
|
4173
4310
|
page,
|
|
4174
4311
|
limit,
|
|
4175
4312
|
archived: req.query.archived === "true",
|
|
@@ -4331,6 +4468,8 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4331
4468
|
const items = await context.getItems({
|
|
4332
4469
|
page: 1,
|
|
4333
4470
|
// todo add pagination
|
|
4471
|
+
user: authenticationResult.user?.id,
|
|
4472
|
+
role: authenticationResult.user?.role?.id,
|
|
4334
4473
|
limit: 500
|
|
4335
4474
|
});
|
|
4336
4475
|
const csv = Papa.unparse(items);
|
|
@@ -4481,7 +4620,8 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4481
4620
|
res,
|
|
4482
4621
|
req
|
|
4483
4622
|
},
|
|
4484
|
-
user:
|
|
4623
|
+
user: user?.id,
|
|
4624
|
+
role: user?.role?.id,
|
|
4485
4625
|
session: headers.session,
|
|
4486
4626
|
message: req.body.message,
|
|
4487
4627
|
tools: enabledTools,
|
|
@@ -4495,8 +4635,9 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4495
4635
|
return;
|
|
4496
4636
|
} else {
|
|
4497
4637
|
const response = await agent.generateSync({
|
|
4498
|
-
user:
|
|
4638
|
+
user: user?.id,
|
|
4499
4639
|
session: headers.session,
|
|
4640
|
+
role: user?.role?.id,
|
|
4500
4641
|
message: req.body.message,
|
|
4501
4642
|
tools: enabledTools.map((tool2) => tool2.tool),
|
|
4502
4643
|
providerApiKey,
|
|
@@ -4595,7 +4736,9 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4595
4736
|
label: "Claude Code",
|
|
4596
4737
|
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
4597
4738
|
trigger: "claude-code",
|
|
4598
|
-
count: 1
|
|
4739
|
+
count: 1,
|
|
4740
|
+
user: authenticationResult.user?.id,
|
|
4741
|
+
role: authenticationResult.user.role?.id
|
|
4599
4742
|
});
|
|
4600
4743
|
response.headers.forEach((value, key) => {
|
|
4601
4744
|
res.setHeader(key, value);
|
|
@@ -4633,6 +4776,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4633
4776
|
}
|
|
4634
4777
|
}
|
|
4635
4778
|
});
|
|
4779
|
+
app.use(express.static("public"));
|
|
4636
4780
|
return app;
|
|
4637
4781
|
};
|
|
4638
4782
|
var createCustomAnthropicStreamingMessage = (message) => {
|
|
@@ -4697,7 +4841,7 @@ var bullmq = {
|
|
|
4697
4841
|
};
|
|
4698
4842
|
|
|
4699
4843
|
// src/registry/workers.ts
|
|
4700
|
-
import * as
|
|
4844
|
+
import * as fs3 from "fs";
|
|
4701
4845
|
import path2 from "path";
|
|
4702
4846
|
var defaultLogsDir = path2.join(process.cwd(), "logs");
|
|
4703
4847
|
var redisConnection;
|
|
@@ -4831,16 +4975,16 @@ var createLogsCleanerWorker = (logsDir) => {
|
|
|
4831
4975
|
global_queues.logs_cleaner,
|
|
4832
4976
|
async (job) => {
|
|
4833
4977
|
console.log(`[EXULU] recurring job ${job.id}.`);
|
|
4834
|
-
const folder =
|
|
4978
|
+
const folder = fs3.readdirSync(logsDir);
|
|
4835
4979
|
const files = folder.filter((file) => file.endsWith(".log"));
|
|
4836
4980
|
const now = /* @__PURE__ */ new Date();
|
|
4837
4981
|
const daysToKeep = job.data.ttld;
|
|
4838
4982
|
const dateToKeep = new Date(now.getTime() - daysToKeep * 24 * 60 * 60 * 1e3);
|
|
4839
4983
|
files.forEach((file) => {
|
|
4840
4984
|
const filePath = path2.join(logsDir, file);
|
|
4841
|
-
const fileStats =
|
|
4985
|
+
const fileStats = fs3.statSync(filePath);
|
|
4842
4986
|
if (fileStats.mtime < dateToKeep) {
|
|
4843
|
-
|
|
4987
|
+
fs3.unlinkSync(filePath);
|
|
4844
4988
|
}
|
|
4845
4989
|
});
|
|
4846
4990
|
},
|
|
@@ -4860,7 +5004,7 @@ var createLogsCleanerWorker = (logsDir) => {
|
|
|
4860
5004
|
|
|
4861
5005
|
// src/mcp/index.ts
|
|
4862
5006
|
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4863
|
-
import { randomUUID } from "crypto";
|
|
5007
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
4864
5008
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
4865
5009
|
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
4866
5010
|
import { z as z2 } from "zod";
|
|
@@ -4954,7 +5098,7 @@ ${code}`
|
|
|
4954
5098
|
transport = this.transports[sessionId];
|
|
4955
5099
|
} else if (!sessionId && isInitializeRequest(req.body)) {
|
|
4956
5100
|
transport = new StreamableHTTPServerTransport({
|
|
4957
|
-
sessionIdGenerator: () =>
|
|
5101
|
+
sessionIdGenerator: () => randomUUID2(),
|
|
4958
5102
|
onsessioninitialized: (sessionId2) => {
|
|
4959
5103
|
this.transports[sessionId2] = transport;
|
|
4960
5104
|
}
|
|
@@ -5022,6 +5166,7 @@ var defaultAgent = new ExuluAgent({
|
|
|
5022
5166
|
description: `Basic agent without any defined tools, that can support MCP's.`,
|
|
5023
5167
|
type: "agent",
|
|
5024
5168
|
capabilities: {
|
|
5169
|
+
text: true,
|
|
5025
5170
|
images: [],
|
|
5026
5171
|
files: [],
|
|
5027
5172
|
audio: [],
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exulu/backend",
|
|
3
3
|
"author": "Qventu Bv.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.16.0",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"private": false,
|
|
7
7
|
"publishConfig": {
|
|
@@ -35,6 +35,10 @@
|
|
|
35
35
|
"@types/bun": "latest",
|
|
36
36
|
"@types/node": "^22.14.0",
|
|
37
37
|
"@types/pg": "^8.15.1",
|
|
38
|
+
"@types/bcrypt": "^5.0.2",
|
|
39
|
+
"@types/cors": "^2.8.18",
|
|
40
|
+
"@types/express": "^5.0.1",
|
|
41
|
+
"@types/graphql-type-json": "^0.3.5",
|
|
38
42
|
"conventional-changelog-atom": "^5.0.0",
|
|
39
43
|
"husky": "^9.1.7",
|
|
40
44
|
"semantic-release": "^24.2.7",
|
|
@@ -51,13 +55,7 @@
|
|
|
51
55
|
"@aws-sdk/client-s3": "^3.338.0",
|
|
52
56
|
"@aws-sdk/client-sts": "^3.338.0",
|
|
53
57
|
"@aws-sdk/s3-request-presigner": "^3.338.0",
|
|
54
|
-
"@inkjs/ui": "^2.0.0",
|
|
55
58
|
"@modelcontextprotocol/sdk": "^1.14.0",
|
|
56
|
-
"@types/bcrypt": "^5.0.2",
|
|
57
|
-
"@types/cors": "^2.8.18",
|
|
58
|
-
"@types/express": "^5.0.1",
|
|
59
|
-
"@types/graphql-type-json": "^0.3.5",
|
|
60
|
-
"@types/multer": "^1.4.12",
|
|
61
59
|
"ai": "^5.0.15",
|
|
62
60
|
"apollo-server": "^3.13.0",
|
|
63
61
|
"bcryptjs": "^3.0.2",
|
|
@@ -69,21 +67,14 @@
|
|
|
69
67
|
"csv-parse": "^5.6.0",
|
|
70
68
|
"dotenv": "^16.5.0",
|
|
71
69
|
"express": "^5.1.0",
|
|
72
|
-
"fullscreen-ink": "^0.0.2",
|
|
73
70
|
"graphql": "^16.11.0",
|
|
74
71
|
"graphql-tools": "^9.0.18",
|
|
75
72
|
"graphql-type-json": "^0.3.2",
|
|
76
73
|
"http-proxy-middleware": "^3.0.5",
|
|
77
|
-
"ink": "^6.0.0",
|
|
78
|
-
"ink-big-text": "^2.0.0",
|
|
79
|
-
"ink-gradient": "^3.0.0",
|
|
80
|
-
"ink-select-input": "^6.2.0",
|
|
81
|
-
"ink-table": "^3.1.0",
|
|
82
74
|
"jose": "^6.0.10",
|
|
83
75
|
"jsonwebtoken": "^9.0.2",
|
|
84
76
|
"knex": "^3.1.0",
|
|
85
77
|
"link": "^2.1.1",
|
|
86
|
-
"multer": "^1.4.5-lts.2",
|
|
87
78
|
"openai": "^4.94.0",
|
|
88
79
|
"papaparse": "^5.5.2",
|
|
89
80
|
"pg": "^8.16.3",
|
|
@@ -91,7 +82,6 @@
|
|
|
91
82
|
"redis": "^4.7.0",
|
|
92
83
|
"reflect-metadata": "^0.2.2",
|
|
93
84
|
"tiktoken": "^1.0.21",
|
|
94
|
-
"type-graphql": "^2.0.0-rc.2",
|
|
95
85
|
"uninstall": "^0.0.0",
|
|
96
86
|
"uuid": "^11.1.0",
|
|
97
87
|
"zod": "^3.24.2",
|
package/types/models/agent.ts
CHANGED