@exulu/backend 1.5.0 → 1.6.1
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 +432 -404
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +430 -403
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -45,7 +45,8 @@ __export(index_exports, {
|
|
|
45
45
|
ExuluSource: () => ExuluSource,
|
|
46
46
|
ExuluTool: () => ExuluTool,
|
|
47
47
|
ExuluWorkflow: () => ExuluWorkflow,
|
|
48
|
-
ExuluZodFileType: () => ExuluZodFileType
|
|
48
|
+
ExuluZodFileType: () => ExuluZodFileType,
|
|
49
|
+
db: () => db2
|
|
49
50
|
});
|
|
50
51
|
module.exports = __toCommonJS(index_exports);
|
|
51
52
|
var import_config = require("dotenv/config");
|
|
@@ -142,6 +143,36 @@ var import_knex = __toESM(require("knex"), 1);
|
|
|
142
143
|
var import_knex2 = require("knex");
|
|
143
144
|
var import_knex3 = require("pgvector/knex");
|
|
144
145
|
var db = {};
|
|
146
|
+
var databaseExistsChecked = false;
|
|
147
|
+
async function ensureDatabaseExists() {
|
|
148
|
+
console.log("[EXULU] Ensuring exulu database exists...");
|
|
149
|
+
const defaultKnex = (0, import_knex.default)({
|
|
150
|
+
client: "pg",
|
|
151
|
+
connection: {
|
|
152
|
+
host: process.env.POSTGRES_DB_HOST,
|
|
153
|
+
port: parseInt(process.env.POSTGRES_DB_PORT || "5432"),
|
|
154
|
+
user: process.env.POSTGRES_DB_USER,
|
|
155
|
+
database: "postgres",
|
|
156
|
+
// Connect to default database
|
|
157
|
+
password: process.env.POSTGRES_DB_PASSWORD,
|
|
158
|
+
ssl: process.env.POSTGRES_DB_SSL === "true" ? { rejectUnauthorized: false } : false
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
try {
|
|
162
|
+
const result = await defaultKnex.raw(`
|
|
163
|
+
SELECT 1 FROM pg_database WHERE datname = 'exulu'
|
|
164
|
+
`);
|
|
165
|
+
if (result.rows.length === 0) {
|
|
166
|
+
console.log("[EXULU] Database 'exulu' does not exist. Creating it...");
|
|
167
|
+
await defaultKnex.raw(`CREATE DATABASE exulu`);
|
|
168
|
+
console.log("[EXULU] Database 'exulu' created successfully.");
|
|
169
|
+
} else {
|
|
170
|
+
console.log("[EXULU] Database 'exulu' already exists.");
|
|
171
|
+
}
|
|
172
|
+
} finally {
|
|
173
|
+
await defaultKnex.destroy();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
145
176
|
async function postgresClient() {
|
|
146
177
|
if (!db["exulu"]) {
|
|
147
178
|
try {
|
|
@@ -151,6 +182,12 @@ async function postgresClient() {
|
|
|
151
182
|
console.log("[EXULU] POSTGRES_DB_USER:", process.env.POSTGRES_DB_USER);
|
|
152
183
|
console.log("[EXULU] POSTGRES_DB_PASSWORD:", process.env.POSTGRES_DB_PASSWORD);
|
|
153
184
|
console.log("[EXULU] POSTGRES_DB_SSL:", process.env.POSTGRES_DB_SSL);
|
|
185
|
+
console.log("[EXULU] Database exists checked:", databaseExistsChecked);
|
|
186
|
+
if (!databaseExistsChecked) {
|
|
187
|
+
console.log("[EXULU] Ensuring exulu database exists...");
|
|
188
|
+
await ensureDatabaseExists();
|
|
189
|
+
databaseExistsChecked = true;
|
|
190
|
+
}
|
|
154
191
|
const knex = (0, import_knex.default)({
|
|
155
192
|
client: "pg",
|
|
156
193
|
connection: {
|
|
@@ -224,7 +261,7 @@ var bullmqDecorator = async ({
|
|
|
224
261
|
jobId: redisId
|
|
225
262
|
}
|
|
226
263
|
);
|
|
227
|
-
const { db:
|
|
264
|
+
const { db: db3 } = await postgresClient();
|
|
228
265
|
const now = /* @__PURE__ */ new Date();
|
|
229
266
|
console.log("[EXULU] scheduling new job", inputs);
|
|
230
267
|
const insertData = {
|
|
@@ -249,12 +286,12 @@ var bullmqDecorator = async ({
|
|
|
249
286
|
...documents && { documents: documents.map((doc2) => doc2.id) },
|
|
250
287
|
...trigger && { trigger }
|
|
251
288
|
};
|
|
252
|
-
await
|
|
289
|
+
await db3("jobs").insert(insertData).onConflict("redis").merge({
|
|
253
290
|
...insertData,
|
|
254
291
|
updatedAt: now
|
|
255
292
|
// Only updatedAt changes on updates
|
|
256
293
|
});
|
|
257
|
-
const doc = await
|
|
294
|
+
const doc = await db3.from("jobs").where({ redis: job.id }).first();
|
|
258
295
|
if (!doc?.id) {
|
|
259
296
|
throw new Error("Failed to get job ID after insert/update");
|
|
260
297
|
}
|
|
@@ -657,10 +694,10 @@ var ExuluWorkflow = class {
|
|
|
657
694
|
label
|
|
658
695
|
}) => {
|
|
659
696
|
let inputs;
|
|
660
|
-
const { db:
|
|
697
|
+
const { db: db3 } = await postgresClient();
|
|
661
698
|
if (!job?.id) {
|
|
662
699
|
logger.write(`Creating new job for workflow ${this.name} with inputs: ${JSON.stringify(initialInputs)}`, "INFO");
|
|
663
|
-
const result = await
|
|
700
|
+
const result = await db3("jobs").insert({
|
|
664
701
|
status: JOB_STATUS_ENUM.active,
|
|
665
702
|
name: `Job running '${this.name}' for '${label}'`,
|
|
666
703
|
agent,
|
|
@@ -678,7 +715,7 @@ var ExuluWorkflow = class {
|
|
|
678
715
|
throw new Error("Job not found, or failed to be created.");
|
|
679
716
|
}
|
|
680
717
|
if (job.status !== JOB_STATUS_ENUM.active) {
|
|
681
|
-
await
|
|
718
|
+
await db3("jobs").update({
|
|
682
719
|
status: JOB_STATUS_ENUM.active,
|
|
683
720
|
inputs: initialInputs
|
|
684
721
|
}).where({ id: job?.id }).returning("id");
|
|
@@ -721,15 +758,15 @@ var ExuluWorkflow = class {
|
|
|
721
758
|
logger.write(`Step ${step.name} output: ${JSON.stringify(result)}`, "INFO");
|
|
722
759
|
final = result;
|
|
723
760
|
}
|
|
724
|
-
await
|
|
761
|
+
await db3("jobs").update({
|
|
725
762
|
status: JOB_STATUS_ENUM.completed,
|
|
726
763
|
result: JSON.stringify(final),
|
|
727
|
-
finished_at:
|
|
764
|
+
finished_at: db3.fn.now()
|
|
728
765
|
}).where({ id: job?.id }).returning("id");
|
|
729
766
|
return final;
|
|
730
767
|
} catch (error) {
|
|
731
768
|
logger.write(`Workflow ${this.name} failed with error: ${error.message} for job ${job?.id}`, "ERROR");
|
|
732
|
-
await
|
|
769
|
+
await db3("jobs").update({
|
|
733
770
|
status: JOB_STATUS_ENUM.failed,
|
|
734
771
|
result: JSON.stringify({
|
|
735
772
|
error: error.message || error,
|
|
@@ -842,8 +879,8 @@ var ExuluEval = class {
|
|
|
842
879
|
</correct_answers>`
|
|
843
880
|
});
|
|
844
881
|
console.log("[EXULU] eval result", object);
|
|
845
|
-
const { db:
|
|
846
|
-
await
|
|
882
|
+
const { db: db3 } = await postgresClient();
|
|
883
|
+
await db3("eval_results").insert({
|
|
847
884
|
input: data.prompt,
|
|
848
885
|
output: data.result,
|
|
849
886
|
duration: data.duration,
|
|
@@ -854,8 +891,8 @@ var ExuluEval = class {
|
|
|
854
891
|
comment: object.comment,
|
|
855
892
|
category: data.category,
|
|
856
893
|
metadata: data.metadata,
|
|
857
|
-
createdAt:
|
|
858
|
-
updatedAt:
|
|
894
|
+
createdAt: db3.fn.now(),
|
|
895
|
+
updatedAt: db3.fn.now()
|
|
859
896
|
});
|
|
860
897
|
return {
|
|
861
898
|
score: object.correctnessScore,
|
|
@@ -959,15 +996,15 @@ var ExuluContext = class {
|
|
|
959
996
|
return sanitizeName(this.name) + "_chunks";
|
|
960
997
|
};
|
|
961
998
|
tableExists = async () => {
|
|
962
|
-
const { db:
|
|
963
|
-
const tableExists = await
|
|
999
|
+
const { db: db3 } = await postgresClient();
|
|
1000
|
+
const tableExists = await db3.schema.hasTable(this.getTableName());
|
|
964
1001
|
return tableExists;
|
|
965
1002
|
};
|
|
966
1003
|
async updateItem(user, id, item) {
|
|
967
1004
|
if (!id) {
|
|
968
1005
|
throw new Error("Id is required for updating an item.");
|
|
969
1006
|
}
|
|
970
|
-
const { db:
|
|
1007
|
+
const { db: db3 } = await postgresClient();
|
|
971
1008
|
Object.keys(item).forEach((key) => {
|
|
972
1009
|
if (key === "name" || key === "description" || key === "external_id" || key === "tags" || key === "source" || key === "textLength" || key === "upsert" || key === "archived") {
|
|
973
1010
|
return;
|
|
@@ -980,8 +1017,8 @@ var ExuluContext = class {
|
|
|
980
1017
|
delete item.id;
|
|
981
1018
|
delete item.created_at;
|
|
982
1019
|
delete item.upsert;
|
|
983
|
-
item.updated_at =
|
|
984
|
-
const result = await
|
|
1020
|
+
item.updated_at = db3.fn.now();
|
|
1021
|
+
const result = await db3.from(this.getTableName()).where({ id }).update(item).returning("id");
|
|
985
1022
|
if (this.configuration.calculateVectors === "onUpdate" || this.configuration.calculateVectors === "always") {
|
|
986
1023
|
if (this.embedder.queue?.name) {
|
|
987
1024
|
console.log("[EXULU] embedder is in queue mode, scheduling job.");
|
|
@@ -1005,18 +1042,18 @@ var ExuluContext = class {
|
|
|
1005
1042
|
label: this.name,
|
|
1006
1043
|
trigger: "agent"
|
|
1007
1044
|
});
|
|
1008
|
-
const exists = await
|
|
1045
|
+
const exists = await db3.schema.hasTable(this.getChunksTableName());
|
|
1009
1046
|
if (!exists) {
|
|
1010
1047
|
await this.createChunksTable();
|
|
1011
1048
|
}
|
|
1012
|
-
await
|
|
1013
|
-
await
|
|
1049
|
+
await db3.from(this.getChunksTableName()).where({ source }).delete();
|
|
1050
|
+
await db3.from(this.getChunksTableName()).insert(chunks.map((chunk) => ({
|
|
1014
1051
|
source,
|
|
1015
1052
|
content: chunk.content,
|
|
1016
1053
|
chunk_index: chunk.index,
|
|
1017
1054
|
embedding: import_knex4.default.toSql(chunk.vector)
|
|
1018
1055
|
})));
|
|
1019
|
-
await
|
|
1056
|
+
await db3.from(this.getTableName()).where({ id }).update({
|
|
1020
1057
|
embeddings_updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1021
1058
|
}).returning("id");
|
|
1022
1059
|
}
|
|
@@ -1029,9 +1066,9 @@ var ExuluContext = class {
|
|
|
1029
1066
|
if (!item.name) {
|
|
1030
1067
|
throw new Error("Name field is required.");
|
|
1031
1068
|
}
|
|
1032
|
-
const { db:
|
|
1069
|
+
const { db: db3 } = await postgresClient();
|
|
1033
1070
|
if (item.external_id) {
|
|
1034
|
-
const existingItem = await
|
|
1071
|
+
const existingItem = await db3.from(this.getTableName()).where({ external_id: item.external_id }).first();
|
|
1035
1072
|
if (existingItem && !upsert) {
|
|
1036
1073
|
throw new Error("Item with external id " + item.external_id + " already exists.");
|
|
1037
1074
|
}
|
|
@@ -1041,7 +1078,7 @@ var ExuluContext = class {
|
|
|
1041
1078
|
}
|
|
1042
1079
|
}
|
|
1043
1080
|
if (upsert && item.id) {
|
|
1044
|
-
const existingItem = await
|
|
1081
|
+
const existingItem = await db3.from(this.getTableName()).where({ id: item.id }).first();
|
|
1045
1082
|
if (existingItem && upsert) {
|
|
1046
1083
|
await this.updateItem(user, existingItem.id, item);
|
|
1047
1084
|
return existingItem.id;
|
|
@@ -1058,11 +1095,11 @@ var ExuluContext = class {
|
|
|
1058
1095
|
});
|
|
1059
1096
|
delete item.id;
|
|
1060
1097
|
delete item.upsert;
|
|
1061
|
-
const result = await
|
|
1098
|
+
const result = await db3.from(this.getTableName()).insert({
|
|
1062
1099
|
...item,
|
|
1063
|
-
id:
|
|
1064
|
-
created_at:
|
|
1065
|
-
updated_at:
|
|
1100
|
+
id: db3.fn.uuid(),
|
|
1101
|
+
created_at: db3.fn.now(),
|
|
1102
|
+
updated_at: db3.fn.now()
|
|
1066
1103
|
}).returning("id");
|
|
1067
1104
|
if (this.configuration.calculateVectors === "onInsert" || this.configuration.calculateVectors === "always") {
|
|
1068
1105
|
if (this.embedder.queue?.name) {
|
|
@@ -1088,18 +1125,18 @@ var ExuluContext = class {
|
|
|
1088
1125
|
label: this.name,
|
|
1089
1126
|
trigger: "agent"
|
|
1090
1127
|
});
|
|
1091
|
-
const exists = await
|
|
1128
|
+
const exists = await db3.schema.hasTable(this.getChunksTableName());
|
|
1092
1129
|
if (!exists) {
|
|
1093
1130
|
await this.createChunksTable();
|
|
1094
1131
|
}
|
|
1095
1132
|
console.log("[EXULU] Inserting chunks.");
|
|
1096
|
-
await
|
|
1133
|
+
await db3.from(this.getChunksTableName()).insert(chunks.map((chunk) => ({
|
|
1097
1134
|
source,
|
|
1098
1135
|
content: chunk.content,
|
|
1099
1136
|
chunk_index: chunk.index,
|
|
1100
1137
|
embedding: import_knex4.default.toSql(chunk.vector)
|
|
1101
1138
|
})));
|
|
1102
|
-
await
|
|
1139
|
+
await db3.from(this.getTableName()).where({ id: result[0].id }).update({
|
|
1103
1140
|
embeddings_updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1104
1141
|
}).returning("id");
|
|
1105
1142
|
}
|
|
@@ -1129,10 +1166,10 @@ var ExuluContext = class {
|
|
|
1129
1166
|
if (limit < 1) limit = 10;
|
|
1130
1167
|
let offset = (page - 1) * limit;
|
|
1131
1168
|
const mainTable = this.getTableName();
|
|
1132
|
-
const { db:
|
|
1133
|
-
const columns = await
|
|
1134
|
-
const totalQuery =
|
|
1135
|
-
const itemsQuery =
|
|
1169
|
+
const { db: db3 } = await postgresClient();
|
|
1170
|
+
const columns = await db3(mainTable).columnInfo();
|
|
1171
|
+
const totalQuery = db3.count("* as count").from(mainTable).first();
|
|
1172
|
+
const itemsQuery = db3.select(Object.keys(columns).map((column) => mainTable + "." + column)).from(mainTable).offset(offset).limit(limit);
|
|
1136
1173
|
if (sort) {
|
|
1137
1174
|
itemsQuery.orderBy(sort, order === "desc" ? "desc" : "asc");
|
|
1138
1175
|
}
|
|
@@ -1208,29 +1245,29 @@ var ExuluContext = class {
|
|
|
1208
1245
|
const vectorExpr = `${vectorStr}::vector`;
|
|
1209
1246
|
switch (method) {
|
|
1210
1247
|
case "l1Distance":
|
|
1211
|
-
itemsQuery.select(
|
|
1212
|
-
itemsQuery.orderByRaw(
|
|
1248
|
+
itemsQuery.select(db3.raw(`?? <-> ${vectorExpr} as l1_distance`, [`${chunksTable}.embedding`]));
|
|
1249
|
+
itemsQuery.orderByRaw(db3.raw(`?? <-> ${vectorExpr} ASC`, [`${chunksTable}.embedding`]));
|
|
1213
1250
|
break;
|
|
1214
1251
|
case "l2Distance":
|
|
1215
|
-
itemsQuery.select(
|
|
1216
|
-
itemsQuery.orderByRaw(
|
|
1252
|
+
itemsQuery.select(db3.raw(`?? <-> ${vectorExpr} as l2_distance`, [`${chunksTable}.embedding`]));
|
|
1253
|
+
itemsQuery.orderByRaw(db3.raw(`?? <-> ${vectorExpr} ASC`, [`${chunksTable}.embedding`]));
|
|
1217
1254
|
break;
|
|
1218
1255
|
case "hammingDistance":
|
|
1219
|
-
itemsQuery.select(
|
|
1220
|
-
itemsQuery.orderByRaw(
|
|
1256
|
+
itemsQuery.select(db3.raw(`?? <#> ${vectorExpr} as hamming_distance`, [`${chunksTable}.embedding`]));
|
|
1257
|
+
itemsQuery.orderByRaw(db3.raw(`?? <#> ${vectorExpr} ASC`, [`${chunksTable}.embedding`]));
|
|
1221
1258
|
break;
|
|
1222
1259
|
case "jaccardDistance":
|
|
1223
|
-
itemsQuery.select(
|
|
1224
|
-
itemsQuery.orderByRaw(
|
|
1260
|
+
itemsQuery.select(db3.raw(`?? <#> ${vectorExpr} as jaccard_distance`, [`${chunksTable}.embedding`]));
|
|
1261
|
+
itemsQuery.orderByRaw(db3.raw(`?? <#> ${vectorExpr} ASC`, [`${chunksTable}.embedding`]));
|
|
1225
1262
|
break;
|
|
1226
1263
|
case "maxInnerProduct":
|
|
1227
|
-
itemsQuery.select(
|
|
1228
|
-
itemsQuery.orderByRaw(
|
|
1264
|
+
itemsQuery.select(db3.raw(`?? <#> ${vectorExpr} as inner_product`, [`${chunksTable}.embedding`]));
|
|
1265
|
+
itemsQuery.orderByRaw(db3.raw(`?? <#> ${vectorExpr} ASC`, [`${chunksTable}.embedding`]));
|
|
1229
1266
|
break;
|
|
1230
1267
|
case "cosineDistance":
|
|
1231
1268
|
default:
|
|
1232
|
-
itemsQuery.select(
|
|
1233
|
-
itemsQuery.orderByRaw(
|
|
1269
|
+
itemsQuery.select(db3.raw(`1 - (?? <#> ${vectorExpr}) as cosine_distance`, [`${chunksTable}.embedding`]));
|
|
1270
|
+
itemsQuery.orderByRaw(db3.raw(`1 - (?? <#> ${vectorExpr}) DESC`, [`${chunksTable}.embedding`]));
|
|
1234
1271
|
break;
|
|
1235
1272
|
}
|
|
1236
1273
|
let items = await itemsQuery;
|
|
@@ -1299,12 +1336,12 @@ var ExuluContext = class {
|
|
|
1299
1336
|
}
|
|
1300
1337
|
};
|
|
1301
1338
|
createItemsTable = async () => {
|
|
1302
|
-
const { db:
|
|
1339
|
+
const { db: db3 } = await postgresClient();
|
|
1303
1340
|
const tableName = this.getTableName();
|
|
1304
1341
|
console.log("[EXULU] Creating table: " + tableName);
|
|
1305
|
-
return await
|
|
1342
|
+
return await db3.schema.createTable(tableName, (table) => {
|
|
1306
1343
|
console.log("[EXULU] Creating fields for table.", this.fields);
|
|
1307
|
-
table.uuid("id").primary().defaultTo(
|
|
1344
|
+
table.uuid("id").primary().defaultTo(db3.fn.uuid());
|
|
1308
1345
|
table.text("name");
|
|
1309
1346
|
table.text("description");
|
|
1310
1347
|
table.text("tags");
|
|
@@ -1324,11 +1361,11 @@ var ExuluContext = class {
|
|
|
1324
1361
|
});
|
|
1325
1362
|
};
|
|
1326
1363
|
createChunksTable = async () => {
|
|
1327
|
-
const { db:
|
|
1364
|
+
const { db: db3 } = await postgresClient();
|
|
1328
1365
|
const tableName = this.getChunksTableName();
|
|
1329
1366
|
console.log("[EXULU] Creating table: " + tableName);
|
|
1330
|
-
return await
|
|
1331
|
-
table.uuid("id").primary().defaultTo(
|
|
1367
|
+
return await db3.schema.createTable(tableName, (table) => {
|
|
1368
|
+
table.uuid("id").primary().defaultTo(db3.fn.uuid());
|
|
1332
1369
|
table.uuid("source").references("id").inTable(this.getTableName());
|
|
1333
1370
|
table.text("content");
|
|
1334
1371
|
table.integer("chunk_index");
|
|
@@ -1400,15 +1437,15 @@ var ExuluSource = class {
|
|
|
1400
1437
|
};
|
|
1401
1438
|
var updateStatistic = async (statistic) => {
|
|
1402
1439
|
const currentDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1403
|
-
const { db:
|
|
1404
|
-
const existing = await
|
|
1440
|
+
const { db: db3 } = await postgresClient();
|
|
1441
|
+
const existing = await db3.from("statistics").where({
|
|
1405
1442
|
name: statistic.name,
|
|
1406
1443
|
label: statistic.label,
|
|
1407
1444
|
type: statistic.type,
|
|
1408
1445
|
createdAt: currentDate
|
|
1409
1446
|
}).first();
|
|
1410
1447
|
if (!existing) {
|
|
1411
|
-
await
|
|
1448
|
+
await db3.from("statistics").insert({
|
|
1412
1449
|
name: statistic.name,
|
|
1413
1450
|
label: statistic.label,
|
|
1414
1451
|
type: statistic.type,
|
|
@@ -1416,8 +1453,8 @@ var updateStatistic = async (statistic) => {
|
|
|
1416
1453
|
createdAt: currentDate
|
|
1417
1454
|
});
|
|
1418
1455
|
} else {
|
|
1419
|
-
await
|
|
1420
|
-
total:
|
|
1456
|
+
await db3.from("statistics").update({
|
|
1457
|
+
total: db3.raw("total + ?", [statistic.count ?? 1])
|
|
1421
1458
|
}).where({
|
|
1422
1459
|
name: statistic.name,
|
|
1423
1460
|
label: statistic.label,
|
|
@@ -1495,7 +1532,7 @@ var authentication = async ({
|
|
|
1495
1532
|
apikey,
|
|
1496
1533
|
authtoken,
|
|
1497
1534
|
internalkey,
|
|
1498
|
-
db:
|
|
1535
|
+
db: db3
|
|
1499
1536
|
}) => {
|
|
1500
1537
|
if (internalkey) {
|
|
1501
1538
|
if (!process.env.INTERNAL_SECRET) {
|
|
@@ -1532,7 +1569,7 @@ var authentication = async ({
|
|
|
1532
1569
|
code: 401
|
|
1533
1570
|
};
|
|
1534
1571
|
}
|
|
1535
|
-
const user = await
|
|
1572
|
+
const user = await db3.from("users").select("*").where("email", authtoken?.email).first();
|
|
1536
1573
|
if (!user) {
|
|
1537
1574
|
return {
|
|
1538
1575
|
error: true,
|
|
@@ -1555,7 +1592,7 @@ var authentication = async ({
|
|
|
1555
1592
|
}
|
|
1556
1593
|
}
|
|
1557
1594
|
if (apikey) {
|
|
1558
|
-
const users = await
|
|
1595
|
+
const users = await db3.from("users").select("*").where("type", "api");
|
|
1559
1596
|
if (!users || users.length === 0) {
|
|
1560
1597
|
return {
|
|
1561
1598
|
error: true,
|
|
@@ -1587,7 +1624,7 @@ var authentication = async ({
|
|
|
1587
1624
|
const user_key_compare_value = user.apikey.substring(0, user_key_last_slash_index);
|
|
1588
1625
|
const isMatch = await import_bcryptjs.default.compare(request_key_compare_value, user_key_compare_value);
|
|
1589
1626
|
if (isMatch) {
|
|
1590
|
-
await
|
|
1627
|
+
await db3.from("users").where({ id: user.id }).update({
|
|
1591
1628
|
last_used: /* @__PURE__ */ new Date()
|
|
1592
1629
|
}).returning("id");
|
|
1593
1630
|
return {
|
|
@@ -1615,7 +1652,7 @@ var authentication = async ({
|
|
|
1615
1652
|
var requestValidators = {
|
|
1616
1653
|
authenticate: async (req) => {
|
|
1617
1654
|
const apikey = req.headers["exulu-api-key"] || null;
|
|
1618
|
-
const { db:
|
|
1655
|
+
const { db: db3 } = await postgresClient();
|
|
1619
1656
|
let authtoken = null;
|
|
1620
1657
|
if (typeof apikey !== "string") {
|
|
1621
1658
|
authtoken = await getToken((req.headers["authorization"] || req.headers["x-api-key"]) ?? "");
|
|
@@ -1623,7 +1660,7 @@ var requestValidators = {
|
|
|
1623
1660
|
return await authentication({
|
|
1624
1661
|
authtoken,
|
|
1625
1662
|
apikey,
|
|
1626
|
-
db:
|
|
1663
|
+
db: db3
|
|
1627
1664
|
});
|
|
1628
1665
|
},
|
|
1629
1666
|
workflows: (req) => {
|
|
@@ -1966,11 +2003,11 @@ function createMutations(table) {
|
|
|
1966
2003
|
const tableNameSingular = table.name.singular.toLowerCase();
|
|
1967
2004
|
return {
|
|
1968
2005
|
[`${tableNamePlural}CreateOne`]: async (_, args, context, info) => {
|
|
1969
|
-
const { db:
|
|
2006
|
+
const { db: db3 } = context;
|
|
1970
2007
|
const requestedFields = getRequestedFields(info);
|
|
1971
2008
|
let { input } = args;
|
|
1972
2009
|
input = encryptSensitiveFields(input);
|
|
1973
|
-
const results = await
|
|
2010
|
+
const results = await db3(tableNamePlural).insert({
|
|
1974
2011
|
...input,
|
|
1975
2012
|
createdAt: /* @__PURE__ */ new Date(),
|
|
1976
2013
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -1978,43 +2015,43 @@ function createMutations(table) {
|
|
|
1978
2015
|
return results[0];
|
|
1979
2016
|
},
|
|
1980
2017
|
[`${tableNamePlural}UpdateOne`]: async (_, args, context, info) => {
|
|
1981
|
-
const { db:
|
|
2018
|
+
const { db: db3 } = context;
|
|
1982
2019
|
let { where, input } = args;
|
|
1983
2020
|
input = encryptSensitiveFields(input);
|
|
1984
|
-
await
|
|
2021
|
+
await db3(tableNamePlural).where(where).update({
|
|
1985
2022
|
...input,
|
|
1986
2023
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1987
2024
|
});
|
|
1988
2025
|
const requestedFields = getRequestedFields(info);
|
|
1989
|
-
const result = await
|
|
2026
|
+
const result = await db3.from(tableNamePlural).select(requestedFields).where(where).first();
|
|
1990
2027
|
return result;
|
|
1991
2028
|
},
|
|
1992
2029
|
[`${tableNamePlural}UpdateOneById`]: async (_, args, context, info) => {
|
|
1993
2030
|
let { id, input } = args;
|
|
1994
2031
|
input = encryptSensitiveFields(input);
|
|
1995
|
-
const { db:
|
|
1996
|
-
await
|
|
2032
|
+
const { db: db3 } = context;
|
|
2033
|
+
await db3(tableNamePlural).where({ id }).update({
|
|
1997
2034
|
...input,
|
|
1998
2035
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1999
2036
|
});
|
|
2000
2037
|
const requestedFields = getRequestedFields(info);
|
|
2001
|
-
const result = await
|
|
2038
|
+
const result = await db3.from(tableNamePlural).select(requestedFields).where({ id }).first();
|
|
2002
2039
|
return result;
|
|
2003
2040
|
},
|
|
2004
2041
|
[`${tableNamePlural}RemoveOne`]: async (_, args, context, info) => {
|
|
2005
|
-
const { db:
|
|
2042
|
+
const { db: db3 } = context;
|
|
2006
2043
|
const { where } = args;
|
|
2007
2044
|
const requestedFields = getRequestedFields(info);
|
|
2008
|
-
const result = await
|
|
2009
|
-
await
|
|
2045
|
+
const result = await db3.from(tableNamePlural).select(requestedFields).where(where).first();
|
|
2046
|
+
await db3(tableNamePlural).where(where).del();
|
|
2010
2047
|
return result;
|
|
2011
2048
|
},
|
|
2012
2049
|
[`${tableNamePlural}RemoveOneById`]: async (_, args, context, info) => {
|
|
2013
2050
|
const { id } = args;
|
|
2014
|
-
const { db:
|
|
2051
|
+
const { db: db3 } = context;
|
|
2015
2052
|
const requestedFields = getRequestedFields(info);
|
|
2016
|
-
const result = await
|
|
2017
|
-
await
|
|
2053
|
+
const result = await db3.from(tableNamePlural).select(requestedFields).where({ id }).first();
|
|
2054
|
+
await db3(tableNamePlural).where({ id }).del();
|
|
2018
2055
|
return result;
|
|
2019
2056
|
}
|
|
2020
2057
|
};
|
|
@@ -2051,16 +2088,16 @@ function createQueries(table) {
|
|
|
2051
2088
|
};
|
|
2052
2089
|
return {
|
|
2053
2090
|
[`${tableNameSingular}ById`]: async (_, args, context, info) => {
|
|
2054
|
-
const { db:
|
|
2091
|
+
const { db: db3 } = context;
|
|
2055
2092
|
const requestedFields = getRequestedFields(info);
|
|
2056
|
-
const result = await
|
|
2093
|
+
const result = await db3.from(tableNamePlural).select(requestedFields).where({ id: args.id }).first();
|
|
2057
2094
|
return result;
|
|
2058
2095
|
},
|
|
2059
2096
|
[`${tableNameSingular}One`]: async (_, args, context, info) => {
|
|
2060
2097
|
const { filters = [], sort } = args;
|
|
2061
|
-
const { db:
|
|
2098
|
+
const { db: db3 } = context;
|
|
2062
2099
|
const requestedFields = getRequestedFields(info);
|
|
2063
|
-
let query =
|
|
2100
|
+
let query = db3.from(tableNamePlural).select(requestedFields);
|
|
2064
2101
|
query = applyFilters(query, filters);
|
|
2065
2102
|
query = applySorting(query, sort);
|
|
2066
2103
|
const result = await query.first();
|
|
@@ -2068,8 +2105,8 @@ function createQueries(table) {
|
|
|
2068
2105
|
},
|
|
2069
2106
|
[`${tableNamePlural}Pagination`]: async (_, args, context, info) => {
|
|
2070
2107
|
const { limit = 10, page = 0, filters = [], sort } = args;
|
|
2071
|
-
const { db:
|
|
2072
|
-
let baseQuery =
|
|
2108
|
+
const { db: db3 } = context;
|
|
2109
|
+
let baseQuery = db3(tableNamePlural);
|
|
2073
2110
|
baseQuery = applyFilters(baseQuery, filters);
|
|
2074
2111
|
const [{ count }] = await baseQuery.clone().count("* as count");
|
|
2075
2112
|
const itemCount = Number(count);
|
|
@@ -2099,8 +2136,8 @@ function createQueries(table) {
|
|
|
2099
2136
|
...tableNamePlural === "jobs" ? {
|
|
2100
2137
|
jobStatistics: async (_, args, context, info) => {
|
|
2101
2138
|
const { user, agent, from, to } = args;
|
|
2102
|
-
const { db:
|
|
2103
|
-
let query =
|
|
2139
|
+
const { db: db3 } = context;
|
|
2140
|
+
let query = db3("jobs");
|
|
2104
2141
|
if (user) {
|
|
2105
2142
|
query = query.where("user", user);
|
|
2106
2143
|
}
|
|
@@ -2117,7 +2154,7 @@ function createQueries(table) {
|
|
|
2117
2154
|
const [{ completedCount }] = await completedQuery.count("* as completedCount");
|
|
2118
2155
|
const failedQuery = query.clone().where("status", "failed");
|
|
2119
2156
|
const [{ failedCount }] = await failedQuery.count("* as failedCount");
|
|
2120
|
-
const durationQuery = query.clone().where("status", "completed").whereNotNull("duration").select(
|
|
2157
|
+
const durationQuery = query.clone().where("status", "completed").whereNotNull("duration").select(db3.raw('AVG("duration") as averageDuration'));
|
|
2121
2158
|
const [{ averageDuration }] = await durationQuery;
|
|
2122
2159
|
return {
|
|
2123
2160
|
completedCount: Number(completedCount),
|
|
@@ -2634,11 +2671,11 @@ var createUppyRoutes = async (app) => {
|
|
|
2634
2671
|
if (typeof apikey !== "string") {
|
|
2635
2672
|
authtoken = await getToken(req.headers.authorization ?? "");
|
|
2636
2673
|
}
|
|
2637
|
-
const { db:
|
|
2674
|
+
const { db: db3 } = await postgresClient();
|
|
2638
2675
|
const authenticationResult = await authentication({
|
|
2639
2676
|
authtoken,
|
|
2640
2677
|
apikey,
|
|
2641
|
-
db:
|
|
2678
|
+
db: db3
|
|
2642
2679
|
});
|
|
2643
2680
|
if (!authenticationResult.user?.id) {
|
|
2644
2681
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
@@ -2679,7 +2716,7 @@ var createUppyRoutes = async (app) => {
|
|
|
2679
2716
|
app.get("/s3/download", async (req, res, next) => {
|
|
2680
2717
|
const apikey = req.headers["exulu-api-key"] || null;
|
|
2681
2718
|
const internalkey = req.headers["internal-key"] || null;
|
|
2682
|
-
const { db:
|
|
2719
|
+
const { db: db3 } = await postgresClient();
|
|
2683
2720
|
let authtoken = null;
|
|
2684
2721
|
if (typeof apikey !== "string" && typeof internalkey !== "string") {
|
|
2685
2722
|
authtoken = await getToken(req.headers.authorization ?? "");
|
|
@@ -2688,7 +2725,7 @@ var createUppyRoutes = async (app) => {
|
|
|
2688
2725
|
authtoken,
|
|
2689
2726
|
apikey,
|
|
2690
2727
|
internalkey,
|
|
2691
|
-
db:
|
|
2728
|
+
db: db3
|
|
2692
2729
|
});
|
|
2693
2730
|
if (!authenticationResult.user?.id) {
|
|
2694
2731
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
@@ -2752,7 +2789,7 @@ var createUppyRoutes = async (app) => {
|
|
|
2752
2789
|
const generateS3Key = (filename) => `${crypto.randomUUID()}-${filename}`;
|
|
2753
2790
|
const signOnServer = async (req, res, next) => {
|
|
2754
2791
|
const apikey = req.headers["exulu-api-key"] || null;
|
|
2755
|
-
const { db:
|
|
2792
|
+
const { db: db3 } = await postgresClient();
|
|
2756
2793
|
let authtoken = null;
|
|
2757
2794
|
if (typeof apikey !== "string") {
|
|
2758
2795
|
authtoken = await getToken(req.headers.authorization ?? "");
|
|
@@ -2760,7 +2797,7 @@ var createUppyRoutes = async (app) => {
|
|
|
2760
2797
|
const authenticationResult = await authentication({
|
|
2761
2798
|
authtoken,
|
|
2762
2799
|
apikey,
|
|
2763
|
-
db:
|
|
2800
|
+
db: db3
|
|
2764
2801
|
});
|
|
2765
2802
|
if (!authenticationResult.user?.id) {
|
|
2766
2803
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
@@ -2800,7 +2837,7 @@ var createUppyRoutes = async (app) => {
|
|
|
2800
2837
|
});
|
|
2801
2838
|
app.post("/s3/multipart", async (req, res, next) => {
|
|
2802
2839
|
const apikey = req.headers["exulu-api-key"] || null;
|
|
2803
|
-
const { db:
|
|
2840
|
+
const { db: db3 } = await postgresClient();
|
|
2804
2841
|
let authtoken = null;
|
|
2805
2842
|
if (typeof apikey !== "string") {
|
|
2806
2843
|
authtoken = await getToken(req.headers.authorization ?? "");
|
|
@@ -2808,7 +2845,7 @@ var createUppyRoutes = async (app) => {
|
|
|
2808
2845
|
const authenticationResult = await authentication({
|
|
2809
2846
|
authtoken,
|
|
2810
2847
|
apikey,
|
|
2811
|
-
db:
|
|
2848
|
+
db: db3
|
|
2812
2849
|
});
|
|
2813
2850
|
if (!authenticationResult.user?.id) {
|
|
2814
2851
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
@@ -2992,6 +3029,7 @@ var global_queues = {
|
|
|
2992
3029
|
logs_cleaner: "logs-cleaner"
|
|
2993
3030
|
};
|
|
2994
3031
|
var createRecurringJobs = async () => {
|
|
3032
|
+
console.log("[EXULU] creating recurring jobs.");
|
|
2995
3033
|
const recurringJobSchedulersLogs = [];
|
|
2996
3034
|
const queue = queues.use(global_queues.logs_cleaner);
|
|
2997
3035
|
recurringJobSchedulersLogs.push({
|
|
@@ -3019,7 +3057,7 @@ var createRecurringJobs = async () => {
|
|
|
3019
3057
|
}
|
|
3020
3058
|
}
|
|
3021
3059
|
);
|
|
3022
|
-
console.log("
|
|
3060
|
+
console.log("[EXULU] recurring job schedulers:");
|
|
3023
3061
|
console.table(recurringJobSchedulersLogs);
|
|
3024
3062
|
return queue;
|
|
3025
3063
|
};
|
|
@@ -3112,10 +3150,10 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3112
3150
|
if (!authenticationResult.user?.id) {
|
|
3113
3151
|
throw new Error(authenticationResult.message);
|
|
3114
3152
|
}
|
|
3115
|
-
const { db:
|
|
3153
|
+
const { db: db3 } = await postgresClient();
|
|
3116
3154
|
return {
|
|
3117
3155
|
req,
|
|
3118
|
-
db:
|
|
3156
|
+
db: db3
|
|
3119
3157
|
};
|
|
3120
3158
|
}
|
|
3121
3159
|
})
|
|
@@ -3134,8 +3172,8 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3134
3172
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
3135
3173
|
return;
|
|
3136
3174
|
}
|
|
3137
|
-
const { db:
|
|
3138
|
-
const agentsFromDb = await
|
|
3175
|
+
const { db: db3 } = await postgresClient();
|
|
3176
|
+
const agentsFromDb = await db3.from("agents").select("*");
|
|
3139
3177
|
res.status(200).json(agentsFromDb.map((agent) => {
|
|
3140
3178
|
const backend = agents.find((a) => a.id === agent.backend);
|
|
3141
3179
|
if (!backend) {
|
|
@@ -3166,7 +3204,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3166
3204
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
3167
3205
|
return;
|
|
3168
3206
|
}
|
|
3169
|
-
const { db:
|
|
3207
|
+
const { db: db3 } = await postgresClient();
|
|
3170
3208
|
const id = req.params.id;
|
|
3171
3209
|
if (!id) {
|
|
3172
3210
|
res.status(400).json({
|
|
@@ -3174,7 +3212,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3174
3212
|
});
|
|
3175
3213
|
return;
|
|
3176
3214
|
}
|
|
3177
|
-
const agent = await
|
|
3215
|
+
const agent = await db3.from("agents").where({ id }).first();
|
|
3178
3216
|
if (!agent) {
|
|
3179
3217
|
res.status(400).json({
|
|
3180
3218
|
message: "Agent not found in database."
|
|
@@ -3240,7 +3278,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3240
3278
|
if (!id && !external_id) {
|
|
3241
3279
|
throw new Error("Missing id or external_id in request.");
|
|
3242
3280
|
}
|
|
3243
|
-
const { db:
|
|
3281
|
+
const { db: db3 } = await postgresClient();
|
|
3244
3282
|
const context = contexts.find((context2) => context2.id === contextId);
|
|
3245
3283
|
if (!context) {
|
|
3246
3284
|
throw new Error("Context not found in registry.");
|
|
@@ -3249,7 +3287,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3249
3287
|
if (!exists) {
|
|
3250
3288
|
throw new Error("Table with name " + context.getTableName() + " does not exist.");
|
|
3251
3289
|
}
|
|
3252
|
-
const query =
|
|
3290
|
+
const query = db3.from(context.getTableName()).select("id");
|
|
3253
3291
|
if (id) {
|
|
3254
3292
|
query.where({ id });
|
|
3255
3293
|
}
|
|
@@ -3260,11 +3298,11 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3260
3298
|
if (!item) {
|
|
3261
3299
|
return null;
|
|
3262
3300
|
}
|
|
3263
|
-
const chunks = await
|
|
3301
|
+
const chunks = await db3.from(context.getChunksTableName()).where({ source: item.id }).select("id");
|
|
3264
3302
|
if (chunks.length > 0) {
|
|
3265
|
-
await
|
|
3303
|
+
await db3.from(context.getChunksTableName()).where({ source: item.id }).delete();
|
|
3266
3304
|
}
|
|
3267
|
-
const mutation =
|
|
3305
|
+
const mutation = db3.from(context.getTableName()).where({ id: item.id }).delete().returning("id");
|
|
3268
3306
|
const result = await mutation;
|
|
3269
3307
|
return result;
|
|
3270
3308
|
};
|
|
@@ -3319,7 +3357,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3319
3357
|
});
|
|
3320
3358
|
return;
|
|
3321
3359
|
}
|
|
3322
|
-
const { db:
|
|
3360
|
+
const { db: db3 } = await postgresClient();
|
|
3323
3361
|
const context = contexts.find((context2) => context2.id === req.params.context);
|
|
3324
3362
|
if (!context) {
|
|
3325
3363
|
res.status(400).json({
|
|
@@ -3331,11 +3369,11 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3331
3369
|
if (!itemsTableExists) {
|
|
3332
3370
|
await context.createItemsTable();
|
|
3333
3371
|
}
|
|
3334
|
-
const chunksTableExists = await
|
|
3372
|
+
const chunksTableExists = await db3.schema.hasTable(context.getChunksTableName());
|
|
3335
3373
|
if (!chunksTableExists) {
|
|
3336
3374
|
await context.createChunksTable();
|
|
3337
3375
|
}
|
|
3338
|
-
const item = await
|
|
3376
|
+
const item = await db3.from(context.getTableName()).where({ id: req.params.id }).select("*").first();
|
|
3339
3377
|
if (!item) {
|
|
3340
3378
|
res.status(404).json({
|
|
3341
3379
|
message: "Item not found."
|
|
@@ -3343,7 +3381,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3343
3381
|
return;
|
|
3344
3382
|
}
|
|
3345
3383
|
console.log("[EXULU] chunks table name.", context.getChunksTableName());
|
|
3346
|
-
const chunks = await
|
|
3384
|
+
const chunks = await db3.from(context.getChunksTableName()).where({ source: req.params.id }).select("id", "content", "source", "embedding", "chunk_index", "created_at", "updated_at");
|
|
3347
3385
|
console.log("[EXULU] chunks", chunks);
|
|
3348
3386
|
res.status(200).json({
|
|
3349
3387
|
...item,
|
|
@@ -3593,7 +3631,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3593
3631
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
3594
3632
|
return;
|
|
3595
3633
|
}
|
|
3596
|
-
const { db:
|
|
3634
|
+
const { db: db3 } = await postgresClient();
|
|
3597
3635
|
const type = req.body.type;
|
|
3598
3636
|
if (!Object.values(STATISTICS_TYPE_ENUM).includes(type)) {
|
|
3599
3637
|
res.status(400).json({
|
|
@@ -3607,7 +3645,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3607
3645
|
from = new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3);
|
|
3608
3646
|
to = /* @__PURE__ */ new Date();
|
|
3609
3647
|
}
|
|
3610
|
-
const query =
|
|
3648
|
+
const query = db3.from("statistics").select("*");
|
|
3611
3649
|
query.where("name", "count");
|
|
3612
3650
|
query.andWhere("type", type);
|
|
3613
3651
|
query.andWhere("createdAt", ">=", from);
|
|
@@ -3642,7 +3680,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3642
3680
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
3643
3681
|
return;
|
|
3644
3682
|
}
|
|
3645
|
-
const { db:
|
|
3683
|
+
const { db: db3 } = await postgresClient();
|
|
3646
3684
|
let from = new Date(req.body.from);
|
|
3647
3685
|
let to = new Date(req.body.to);
|
|
3648
3686
|
if (!from || !to) {
|
|
@@ -3650,7 +3688,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3650
3688
|
to = /* @__PURE__ */ new Date();
|
|
3651
3689
|
}
|
|
3652
3690
|
let promises2 = Object.values(STATISTICS_TYPE_ENUM).map(async (type) => {
|
|
3653
|
-
const result = await
|
|
3691
|
+
const result = await db3.from("statistics").where("name", "count").andWhere("type", type).andWhere("createdAt", ">=", from).andWhere("createdAt", "<=", to).sum("total as total");
|
|
3654
3692
|
return {
|
|
3655
3693
|
[type]: result[0]?.total || 0
|
|
3656
3694
|
};
|
|
@@ -3671,9 +3709,9 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3671
3709
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
3672
3710
|
return;
|
|
3673
3711
|
}
|
|
3674
|
-
const { db:
|
|
3675
|
-
const statistics = await
|
|
3676
|
-
const response = await
|
|
3712
|
+
const { db: db3 } = await postgresClient();
|
|
3713
|
+
const statistics = await db3("statistics").where("name", "count").andWhere("type", "context.retrieve").sum("total as total").first();
|
|
3714
|
+
const response = await db3("jobs").select(db3.raw(`to_char("createdAt", 'YYYY-MM-DD') as date`)).count("* as count").where("type", "embedder").groupByRaw(`to_char("createdAt", 'YYYY-MM-DD')`).then((rows) => ({
|
|
3677
3715
|
jobs: rows
|
|
3678
3716
|
}));
|
|
3679
3717
|
let jobs = [];
|
|
@@ -3683,7 +3721,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3683
3721
|
count: job.count
|
|
3684
3722
|
}));
|
|
3685
3723
|
}
|
|
3686
|
-
const embeddingsCountResult = await
|
|
3724
|
+
const embeddingsCountResult = await db3("jobs").where("type", "embedder").count("* as count").first();
|
|
3687
3725
|
res.status(200).json({
|
|
3688
3726
|
active: contexts.filter((context) => context.active).length,
|
|
3689
3727
|
inactive: contexts.filter((context) => !context.active).length,
|
|
@@ -3883,8 +3921,8 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
3883
3921
|
});
|
|
3884
3922
|
return;
|
|
3885
3923
|
}
|
|
3886
|
-
const { db:
|
|
3887
|
-
const agentInstance = await
|
|
3924
|
+
const { db: db3 } = await postgresClient();
|
|
3925
|
+
const agentInstance = await db3.from("agents").where({
|
|
3888
3926
|
id: instance
|
|
3889
3927
|
}).first();
|
|
3890
3928
|
if (!agentInstance) {
|
|
@@ -4019,26 +4057,18 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
4019
4057
|
app.use("/gateway/anthropic/:id", import_express3.default.raw({ type: "*/*", limit: REQUEST_SIZE_LIMIT }), async (req, res) => {
|
|
4020
4058
|
const path3 = req.url;
|
|
4021
4059
|
const url = `${TARGET_API}${path3}`;
|
|
4022
|
-
console.log("[PROXY] Manual proxy to:", url);
|
|
4023
|
-
console.log("[PROXY] Method:", req.method);
|
|
4024
|
-
console.log("[PROXY] Headers:", Object.keys(req.headers));
|
|
4025
|
-
console.log("[PROXY] Request body length:", req.body ? req.body.length : 0);
|
|
4026
|
-
console.log("[PROXY] Request model name:", req.body.model);
|
|
4027
|
-
console.log("[PROXY] Request stream:", req.body.stream);
|
|
4028
|
-
console.log("[PROXY] Request messages:", req.body.messages?.length);
|
|
4029
4060
|
try {
|
|
4030
|
-
console.log("[PROXY] Request body tools array length:", req.body.tools?.length);
|
|
4031
4061
|
if (!req.body.tools) {
|
|
4032
4062
|
req.body.tools = [];
|
|
4033
4063
|
}
|
|
4034
4064
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
4035
4065
|
if (!authenticationResult.user?.id) {
|
|
4066
|
+
console.log("[EXULU] failed authentication result", authenticationResult);
|
|
4036
4067
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
4037
4068
|
return;
|
|
4038
4069
|
}
|
|
4039
|
-
|
|
4040
|
-
const
|
|
4041
|
-
const agent = await db2.from("agents").where({
|
|
4070
|
+
const { db: db3 } = await postgresClient();
|
|
4071
|
+
const agent = await db3.from("agents").where({
|
|
4042
4072
|
id: req.params.id
|
|
4043
4073
|
}).first();
|
|
4044
4074
|
if (!agent) {
|
|
@@ -4049,7 +4079,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
4049
4079
|
res.end(Buffer.from(arrayBuffer));
|
|
4050
4080
|
return;
|
|
4051
4081
|
}
|
|
4052
|
-
console.log("[EXULU] agent", agent?.name);
|
|
4082
|
+
console.log("[EXULU] anthropic proxy called for agent:", agent?.name);
|
|
4053
4083
|
if (!process.env.NEXTAUTH_SECRET) {
|
|
4054
4084
|
const arrayBuffer = createCustomAnthropicStreamingMessage(CLAUDE_MESSAGES.missing_nextauth_secret);
|
|
4055
4085
|
res.setHeader("Content-Type", "application/json");
|
|
@@ -4071,14 +4101,11 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
4071
4101
|
};
|
|
4072
4102
|
if (req.headers["accept"]) headers["accept"] = req.headers["accept"];
|
|
4073
4103
|
if (req.headers["user-agent"]) headers["user-agent"] = req.headers["user-agent"];
|
|
4074
|
-
console.log("[EXULU] anthropic api key", anthropicApiKey);
|
|
4075
4104
|
const response = await fetch(url, {
|
|
4076
4105
|
method: req.method,
|
|
4077
4106
|
headers,
|
|
4078
4107
|
body: req.method !== "GET" ? JSON.stringify(req.body) : void 0
|
|
4079
4108
|
});
|
|
4080
|
-
console.log("[PROXY] Response:", response);
|
|
4081
|
-
console.log("[PROXY] Response:", response.body);
|
|
4082
4109
|
await updateStatistic({
|
|
4083
4110
|
name: "count",
|
|
4084
4111
|
label: "Claude Code",
|
|
@@ -4104,14 +4131,12 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
|
4104
4131
|
const { done, value } = await reader.read();
|
|
4105
4132
|
if (done) break;
|
|
4106
4133
|
const chunk = decoder.decode(value, { stream: true });
|
|
4107
|
-
console.log("[PROXY] Chunk:", chunk);
|
|
4108
4134
|
res.write(chunk);
|
|
4109
4135
|
}
|
|
4110
4136
|
res.end();
|
|
4111
4137
|
return;
|
|
4112
4138
|
}
|
|
4113
4139
|
const data = await response.arrayBuffer();
|
|
4114
|
-
console.log("[PROXY] Data:", data);
|
|
4115
4140
|
res.end(Buffer.from(data));
|
|
4116
4141
|
} catch (error) {
|
|
4117
4142
|
console.error("[PROXY] Manual proxy error:", error);
|
|
@@ -4236,8 +4261,8 @@ var defaultLogsDir = import_path.default.join(process.cwd(), "logs");
|
|
|
4236
4261
|
var redisConnection;
|
|
4237
4262
|
var createWorkers = async (queues2, contexts, workflows, _logsDir) => {
|
|
4238
4263
|
if (!redisServer.host || !redisServer.port) {
|
|
4239
|
-
console.error("[EXULU] you are trying to start
|
|
4240
|
-
throw new Error("No redis server configured in the environment, so cannot start
|
|
4264
|
+
console.error("[EXULU] you are trying to start worker, but no redis server is configured in the environment.");
|
|
4265
|
+
throw new Error("No redis server configured in the environment, so cannot start worker.");
|
|
4241
4266
|
}
|
|
4242
4267
|
if (!redisConnection) {
|
|
4243
4268
|
redisConnection = new import_ioredis.default({
|
|
@@ -4251,7 +4276,7 @@ var createWorkers = async (queues2, contexts, workflows, _logsDir) => {
|
|
|
4251
4276
|
const worker = new import_bullmq7.Worker(
|
|
4252
4277
|
`${queue}`,
|
|
4253
4278
|
async (bullmqJob) => {
|
|
4254
|
-
const { db:
|
|
4279
|
+
const { db: db3 } = await postgresClient();
|
|
4255
4280
|
try {
|
|
4256
4281
|
bullmq.validate(bullmqJob);
|
|
4257
4282
|
if (bullmqJob.data.type === "embedder") {
|
|
@@ -4293,19 +4318,19 @@ var createWorkers = async (queues2, contexts, workflows, _logsDir) => {
|
|
|
4293
4318
|
label: context.name,
|
|
4294
4319
|
trigger: bullmqJob.data.trigger || "unknown"
|
|
4295
4320
|
});
|
|
4296
|
-
const mongoRecord = await
|
|
4321
|
+
const mongoRecord = await db3.from("jobs").where({ redis: bullmqJob.id }).first();
|
|
4297
4322
|
if (!mongoRecord) {
|
|
4298
4323
|
throw new Error("Job not found in the database.");
|
|
4299
4324
|
}
|
|
4300
4325
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
4301
4326
|
const duration = (finishedAt.getTime() - new Date(mongoRecord.createdAt).getTime()) / 1e3;
|
|
4302
|
-
await
|
|
4327
|
+
await db3.from("jobs").where({ redis: bullmqJob.id }).update({
|
|
4303
4328
|
status: "completed",
|
|
4304
4329
|
finishedAt,
|
|
4305
4330
|
duration,
|
|
4306
4331
|
result: JSON.stringify(result)
|
|
4307
4332
|
});
|
|
4308
|
-
await
|
|
4333
|
+
await db3.from((void 0).getTableName()).where({ id: result[0].id }).update({
|
|
4309
4334
|
embeddings_updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4310
4335
|
}).returning("id");
|
|
4311
4336
|
return result;
|
|
@@ -4315,14 +4340,14 @@ var createWorkers = async (queues2, contexts, workflows, _logsDir) => {
|
|
|
4315
4340
|
if (!workflow) {
|
|
4316
4341
|
throw new Error(`Workflow ${bullmqJob.data.workflow} not found in the registry.`);
|
|
4317
4342
|
}
|
|
4318
|
-
const exuluJob = await
|
|
4343
|
+
const exuluJob = await db3.from("jobs").where({ redis: bullmqJob.id }).first();
|
|
4319
4344
|
if (!exuluJob) {
|
|
4320
4345
|
throw new Error("Job not found in the database.");
|
|
4321
4346
|
}
|
|
4322
4347
|
const result = await bullmq.process.workflow(bullmqJob, exuluJob, workflow, logsDir);
|
|
4323
4348
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
4324
4349
|
const duration = (finishedAt.getTime() - new Date(exuluJob.createdAt).getTime()) / 1e3;
|
|
4325
|
-
await
|
|
4350
|
+
await db3.from("jobs").where({ redis: bullmqJob.id }).update({
|
|
4326
4351
|
status: "completed",
|
|
4327
4352
|
finishedAt,
|
|
4328
4353
|
duration,
|
|
@@ -4331,7 +4356,7 @@ var createWorkers = async (queues2, contexts, workflows, _logsDir) => {
|
|
|
4331
4356
|
return result;
|
|
4332
4357
|
}
|
|
4333
4358
|
} catch (error) {
|
|
4334
|
-
await
|
|
4359
|
+
await db3.from("jobs").where({ redis: bullmqJob.id }).update({
|
|
4335
4360
|
status: "failed",
|
|
4336
4361
|
finishedAt: /* @__PURE__ */ new Date(),
|
|
4337
4362
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -4703,259 +4728,6 @@ var getTicket = new ExuluTool({
|
|
|
4703
4728
|
}
|
|
4704
4729
|
});
|
|
4705
4730
|
|
|
4706
|
-
// src/auth/generate-key.ts
|
|
4707
|
-
var import_bcryptjs2 = __toESM(require("bcryptjs"), 1);
|
|
4708
|
-
var SALT_ROUNDS = 12;
|
|
4709
|
-
async function encryptString(string) {
|
|
4710
|
-
const hash = await import_bcryptjs2.default.hash(string, SALT_ROUNDS);
|
|
4711
|
-
return hash;
|
|
4712
|
-
}
|
|
4713
|
-
var generateApiKey = async (name, email) => {
|
|
4714
|
-
const { db: db2 } = await postgresClient();
|
|
4715
|
-
console.log("[EXULU] Inserting default user and admin role.");
|
|
4716
|
-
const existingRole = await db2.from("roles").where({ name: "admin" }).first();
|
|
4717
|
-
let roleId;
|
|
4718
|
-
if (!existingRole) {
|
|
4719
|
-
console.log("[EXULU] Creating default admin role.");
|
|
4720
|
-
const role = await db2.from("roles").insert({
|
|
4721
|
-
name: "admin",
|
|
4722
|
-
is_admin: true,
|
|
4723
|
-
agents: []
|
|
4724
|
-
}).returning("id");
|
|
4725
|
-
roleId = role[0].id;
|
|
4726
|
-
} else {
|
|
4727
|
-
roleId = existingRole.id;
|
|
4728
|
-
}
|
|
4729
|
-
const newKeyName = name;
|
|
4730
|
-
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
4731
|
-
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
4732
|
-
const encryptedKey = await encryptString(plainKey);
|
|
4733
|
-
const existingApiUser = await db2.from("users").where({ email }).first();
|
|
4734
|
-
if (!existingApiUser) {
|
|
4735
|
-
console.log("[EXULU] Creating default api user.");
|
|
4736
|
-
await db2.from("users").insert({
|
|
4737
|
-
name,
|
|
4738
|
-
email,
|
|
4739
|
-
super_admin: true,
|
|
4740
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
4741
|
-
updatedAt: /* @__PURE__ */ new Date(),
|
|
4742
|
-
type: "api",
|
|
4743
|
-
emailVerified: /* @__PURE__ */ new Date(),
|
|
4744
|
-
apikey: `${encryptedKey}${postFix}`,
|
|
4745
|
-
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
4746
|
-
role: roleId
|
|
4747
|
-
});
|
|
4748
|
-
console.log("[EXULU] Default api user created. Key: ", `${plainKey}${postFix}`);
|
|
4749
|
-
} else {
|
|
4750
|
-
console.log("[EXULU] API user with that name already exists.");
|
|
4751
|
-
}
|
|
4752
|
-
console.log("[EXULU] Key generated, copy and use the plain key from here, you will not be able to access it again.");
|
|
4753
|
-
console.log("[EXULU] Key: ", `${plainKey}${postFix}`);
|
|
4754
|
-
return {
|
|
4755
|
-
key: `${plainKey}${postFix}`
|
|
4756
|
-
};
|
|
4757
|
-
};
|
|
4758
|
-
|
|
4759
|
-
// src/postgres/init-db.ts
|
|
4760
|
-
var up = async function(knex) {
|
|
4761
|
-
if (!await knex.schema.hasTable("agent_sessions")) {
|
|
4762
|
-
console.log("[EXULU] Creating agent_sessions table.");
|
|
4763
|
-
await knex.schema.createTable("agent_sessions", (table) => {
|
|
4764
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4765
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4766
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4767
|
-
for (const field of agentSessionsSchema.fields) {
|
|
4768
|
-
const { type, name, default: defaultValue } = field;
|
|
4769
|
-
if (!type || !name) {
|
|
4770
|
-
continue;
|
|
4771
|
-
}
|
|
4772
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4773
|
-
}
|
|
4774
|
-
});
|
|
4775
|
-
}
|
|
4776
|
-
if (!await knex.schema.hasTable("agent_messages")) {
|
|
4777
|
-
console.log("[EXULU] Creating agent_messages table.");
|
|
4778
|
-
await knex.schema.createTable("agent_messages", (table) => {
|
|
4779
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4780
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4781
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4782
|
-
for (const field of agentMessagesSchema.fields) {
|
|
4783
|
-
const { type, name, default: defaultValue } = field;
|
|
4784
|
-
if (!type || !name) {
|
|
4785
|
-
continue;
|
|
4786
|
-
}
|
|
4787
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4788
|
-
}
|
|
4789
|
-
});
|
|
4790
|
-
}
|
|
4791
|
-
if (!await knex.schema.hasTable("roles")) {
|
|
4792
|
-
console.log("[EXULU] Creating roles table.");
|
|
4793
|
-
await knex.schema.createTable("roles", (table) => {
|
|
4794
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4795
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4796
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4797
|
-
for (const field of rolesSchema.fields) {
|
|
4798
|
-
const { type, name, default: defaultValue } = field;
|
|
4799
|
-
if (!type || !name) {
|
|
4800
|
-
continue;
|
|
4801
|
-
}
|
|
4802
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4803
|
-
}
|
|
4804
|
-
});
|
|
4805
|
-
}
|
|
4806
|
-
if (!await knex.schema.hasTable("eval_results")) {
|
|
4807
|
-
console.log("[EXULU] Creating eval_results table.");
|
|
4808
|
-
await knex.schema.createTable("eval_results", (table) => {
|
|
4809
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4810
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4811
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4812
|
-
for (const field of evalResultsSchema.fields) {
|
|
4813
|
-
const { type, name, default: defaultValue } = field;
|
|
4814
|
-
if (!type || !name) {
|
|
4815
|
-
continue;
|
|
4816
|
-
}
|
|
4817
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4818
|
-
}
|
|
4819
|
-
});
|
|
4820
|
-
}
|
|
4821
|
-
if (!await knex.schema.hasTable("statistics")) {
|
|
4822
|
-
console.log("[EXULU] Creating statistics table.");
|
|
4823
|
-
await knex.schema.createTable("statistics", (table) => {
|
|
4824
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4825
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4826
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4827
|
-
for (const field of statisticsSchema.fields) {
|
|
4828
|
-
const { type, name, default: defaultValue } = field;
|
|
4829
|
-
if (!type || !name) {
|
|
4830
|
-
continue;
|
|
4831
|
-
}
|
|
4832
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4833
|
-
}
|
|
4834
|
-
});
|
|
4835
|
-
}
|
|
4836
|
-
if (!await knex.schema.hasTable("jobs")) {
|
|
4837
|
-
console.log("[EXULU] Creating jobs table.");
|
|
4838
|
-
await knex.schema.createTable("jobs", (table) => {
|
|
4839
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4840
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4841
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4842
|
-
for (const field of jobsSchema.fields) {
|
|
4843
|
-
const { type, name, default: defaultValue } = field;
|
|
4844
|
-
if (!type || !name) {
|
|
4845
|
-
continue;
|
|
4846
|
-
}
|
|
4847
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4848
|
-
}
|
|
4849
|
-
});
|
|
4850
|
-
}
|
|
4851
|
-
if (!await knex.schema.hasTable("agents")) {
|
|
4852
|
-
console.log("[EXULU] Creating agents table.");
|
|
4853
|
-
await knex.schema.createTable("agents", (table) => {
|
|
4854
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4855
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4856
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4857
|
-
for (const field of agentsSchema.fields) {
|
|
4858
|
-
const { type, name, default: defaultValue } = field;
|
|
4859
|
-
if (!type || !name) {
|
|
4860
|
-
continue;
|
|
4861
|
-
}
|
|
4862
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4863
|
-
}
|
|
4864
|
-
});
|
|
4865
|
-
}
|
|
4866
|
-
if (!await knex.schema.hasTable("verification_token")) {
|
|
4867
|
-
console.log("[EXULU] Creating verification_token table.");
|
|
4868
|
-
await knex.schema.createTable("verification_token", (table) => {
|
|
4869
|
-
table.text("identifier").notNullable();
|
|
4870
|
-
table.timestamp("expires", { useTz: true }).notNullable();
|
|
4871
|
-
table.text("token").notNullable();
|
|
4872
|
-
table.primary(["identifier", "token"]);
|
|
4873
|
-
});
|
|
4874
|
-
}
|
|
4875
|
-
if (!await knex.schema.hasTable("users")) {
|
|
4876
|
-
console.log("[EXULU] Creating users table.");
|
|
4877
|
-
await knex.schema.createTable("users", (table) => {
|
|
4878
|
-
table.increments("id").primary();
|
|
4879
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4880
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4881
|
-
table.string("name", 255);
|
|
4882
|
-
table.string("password", 255);
|
|
4883
|
-
table.string("email", 255);
|
|
4884
|
-
table.timestamp("emailVerified", { useTz: true });
|
|
4885
|
-
table.text("image");
|
|
4886
|
-
for (const field of usersSchema.fields) {
|
|
4887
|
-
console.log("[EXULU] field", field);
|
|
4888
|
-
const { type, name, default: defaultValue } = field;
|
|
4889
|
-
if (name === "id" || name === "name" || name === "email" || name === "emailVerified" || name === "image") {
|
|
4890
|
-
continue;
|
|
4891
|
-
}
|
|
4892
|
-
if (!type || !name) {
|
|
4893
|
-
continue;
|
|
4894
|
-
}
|
|
4895
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4896
|
-
}
|
|
4897
|
-
});
|
|
4898
|
-
}
|
|
4899
|
-
if (!await knex.schema.hasTable("accounts")) {
|
|
4900
|
-
console.log("[EXULU] Creating accounts table.");
|
|
4901
|
-
await knex.schema.createTable("accounts", (table) => {
|
|
4902
|
-
table.increments("id").primary();
|
|
4903
|
-
table.integer("userId").notNullable();
|
|
4904
|
-
table.string("type", 255).notNullable();
|
|
4905
|
-
table.string("provider", 255).notNullable();
|
|
4906
|
-
table.string("providerAccountId", 255).notNullable();
|
|
4907
|
-
table.text("refresh_token");
|
|
4908
|
-
table.text("access_token");
|
|
4909
|
-
table.bigInteger("expires_at");
|
|
4910
|
-
table.text("id_token");
|
|
4911
|
-
table.text("scope");
|
|
4912
|
-
table.text("session_state");
|
|
4913
|
-
table.text("token_type");
|
|
4914
|
-
});
|
|
4915
|
-
}
|
|
4916
|
-
};
|
|
4917
|
-
var execute = async () => {
|
|
4918
|
-
const { db: db2 } = await postgresClient();
|
|
4919
|
-
console.log("[EXULU] Checking Exulu IMP database status.");
|
|
4920
|
-
await up(db2);
|
|
4921
|
-
console.log("[EXULU] Inserting default user and admin role.");
|
|
4922
|
-
const existingRole = await db2.from("roles").where({ name: "admin" }).first();
|
|
4923
|
-
let roleId;
|
|
4924
|
-
if (!existingRole) {
|
|
4925
|
-
console.log("[EXULU] Creating default admin role.");
|
|
4926
|
-
const role = await db2.from("roles").insert({
|
|
4927
|
-
name: "admin",
|
|
4928
|
-
is_admin: true,
|
|
4929
|
-
agents: JSON.stringify([])
|
|
4930
|
-
}).returning("id");
|
|
4931
|
-
roleId = role[0].id;
|
|
4932
|
-
} else {
|
|
4933
|
-
roleId = existingRole.id;
|
|
4934
|
-
}
|
|
4935
|
-
const existingUser = await db2.from("users").where({ email: "admin@exulu.com" }).first();
|
|
4936
|
-
if (!existingUser) {
|
|
4937
|
-
const password = await encryptString("admin");
|
|
4938
|
-
console.log("[EXULU] Creating default admin user.");
|
|
4939
|
-
await db2.from("users").insert({
|
|
4940
|
-
name: "exulu",
|
|
4941
|
-
email: "admin@exulu.com",
|
|
4942
|
-
super_admin: true,
|
|
4943
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
4944
|
-
emailVerified: /* @__PURE__ */ new Date(),
|
|
4945
|
-
updatedAt: /* @__PURE__ */ new Date(),
|
|
4946
|
-
password,
|
|
4947
|
-
type: "user",
|
|
4948
|
-
role: roleId
|
|
4949
|
-
});
|
|
4950
|
-
}
|
|
4951
|
-
const { key } = await generateApiKey("exulu", "api@exulu.com");
|
|
4952
|
-
console.log("[EXULU] Database initialized.");
|
|
4953
|
-
console.log("[EXULU] Default api key: ", `${key}`);
|
|
4954
|
-
console.log("[EXULU] Default password if using password auth: ", `admin`);
|
|
4955
|
-
console.log("[EXULU] Default email if using password auth: ", `admin@exulu.com`);
|
|
4956
|
-
return;
|
|
4957
|
-
};
|
|
4958
|
-
|
|
4959
4731
|
// src/registry/index.ts
|
|
4960
4732
|
var ExuluApp = class {
|
|
4961
4733
|
_agents = [];
|
|
@@ -4970,7 +4742,6 @@ var ExuluApp = class {
|
|
|
4970
4742
|
// Factory function so we can async
|
|
4971
4743
|
// initialize the MCP server if needed.
|
|
4972
4744
|
create = async ({ contexts, agents, workflows, config, tools }) => {
|
|
4973
|
-
await execute();
|
|
4974
4745
|
this._workflows = workflows ?? [];
|
|
4975
4746
|
this._contexts = contexts ?? {};
|
|
4976
4747
|
this._agents = [
|
|
@@ -6272,6 +6043,257 @@ var SentenceChunker = class _SentenceChunker extends BaseChunker {
|
|
|
6272
6043
|
}
|
|
6273
6044
|
};
|
|
6274
6045
|
|
|
6046
|
+
// src/auth/generate-key.ts
|
|
6047
|
+
var import_bcryptjs2 = __toESM(require("bcryptjs"), 1);
|
|
6048
|
+
var SALT_ROUNDS = 12;
|
|
6049
|
+
async function encryptString(string) {
|
|
6050
|
+
const hash = await import_bcryptjs2.default.hash(string, SALT_ROUNDS);
|
|
6051
|
+
return hash;
|
|
6052
|
+
}
|
|
6053
|
+
var generateApiKey = async (name, email) => {
|
|
6054
|
+
const { db: db3 } = await postgresClient();
|
|
6055
|
+
console.log("[EXULU] Inserting default user and admin role.");
|
|
6056
|
+
const existingRole = await db3.from("roles").where({ name: "admin" }).first();
|
|
6057
|
+
let roleId;
|
|
6058
|
+
if (!existingRole) {
|
|
6059
|
+
console.log("[EXULU] Creating default admin role.");
|
|
6060
|
+
const role = await db3.from("roles").insert({
|
|
6061
|
+
name: "admin",
|
|
6062
|
+
is_admin: true,
|
|
6063
|
+
agents: []
|
|
6064
|
+
}).returning("id");
|
|
6065
|
+
roleId = role[0].id;
|
|
6066
|
+
} else {
|
|
6067
|
+
roleId = existingRole.id;
|
|
6068
|
+
}
|
|
6069
|
+
const newKeyName = name;
|
|
6070
|
+
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
6071
|
+
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
6072
|
+
const encryptedKey = await encryptString(plainKey);
|
|
6073
|
+
const existingApiUser = await db3.from("users").where({ email }).first();
|
|
6074
|
+
if (!existingApiUser) {
|
|
6075
|
+
console.log("[EXULU] Creating default api user.");
|
|
6076
|
+
await db3.from("users").insert({
|
|
6077
|
+
name,
|
|
6078
|
+
email,
|
|
6079
|
+
super_admin: true,
|
|
6080
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
6081
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
6082
|
+
type: "api",
|
|
6083
|
+
emailVerified: /* @__PURE__ */ new Date(),
|
|
6084
|
+
apikey: `${encryptedKey}${postFix}`,
|
|
6085
|
+
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
6086
|
+
role: roleId
|
|
6087
|
+
});
|
|
6088
|
+
console.log("[EXULU] Default api user created. Key: ", `${plainKey}${postFix}`);
|
|
6089
|
+
} else {
|
|
6090
|
+
console.log("[EXULU] API user with that name already exists.");
|
|
6091
|
+
}
|
|
6092
|
+
return {
|
|
6093
|
+
key: `${plainKey}${postFix}`
|
|
6094
|
+
};
|
|
6095
|
+
};
|
|
6096
|
+
|
|
6097
|
+
// src/postgres/init-db.ts
|
|
6098
|
+
var up = async function(knex) {
|
|
6099
|
+
if (!await knex.schema.hasTable("agent_sessions")) {
|
|
6100
|
+
console.log("[EXULU] Creating agent_sessions table.");
|
|
6101
|
+
await knex.schema.createTable("agent_sessions", (table) => {
|
|
6102
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
6103
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
6104
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
6105
|
+
for (const field of agentSessionsSchema.fields) {
|
|
6106
|
+
const { type, name, default: defaultValue } = field;
|
|
6107
|
+
if (!type || !name) {
|
|
6108
|
+
continue;
|
|
6109
|
+
}
|
|
6110
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
6111
|
+
}
|
|
6112
|
+
});
|
|
6113
|
+
}
|
|
6114
|
+
if (!await knex.schema.hasTable("agent_messages")) {
|
|
6115
|
+
console.log("[EXULU] Creating agent_messages table.");
|
|
6116
|
+
await knex.schema.createTable("agent_messages", (table) => {
|
|
6117
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
6118
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
6119
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
6120
|
+
for (const field of agentMessagesSchema.fields) {
|
|
6121
|
+
const { type, name, default: defaultValue } = field;
|
|
6122
|
+
if (!type || !name) {
|
|
6123
|
+
continue;
|
|
6124
|
+
}
|
|
6125
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
6126
|
+
}
|
|
6127
|
+
});
|
|
6128
|
+
}
|
|
6129
|
+
if (!await knex.schema.hasTable("roles")) {
|
|
6130
|
+
console.log("[EXULU] Creating roles table.");
|
|
6131
|
+
await knex.schema.createTable("roles", (table) => {
|
|
6132
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
6133
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
6134
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
6135
|
+
for (const field of rolesSchema.fields) {
|
|
6136
|
+
const { type, name, default: defaultValue } = field;
|
|
6137
|
+
if (!type || !name) {
|
|
6138
|
+
continue;
|
|
6139
|
+
}
|
|
6140
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
6141
|
+
}
|
|
6142
|
+
});
|
|
6143
|
+
}
|
|
6144
|
+
if (!await knex.schema.hasTable("eval_results")) {
|
|
6145
|
+
console.log("[EXULU] Creating eval_results table.");
|
|
6146
|
+
await knex.schema.createTable("eval_results", (table) => {
|
|
6147
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
6148
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
6149
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
6150
|
+
for (const field of evalResultsSchema.fields) {
|
|
6151
|
+
const { type, name, default: defaultValue } = field;
|
|
6152
|
+
if (!type || !name) {
|
|
6153
|
+
continue;
|
|
6154
|
+
}
|
|
6155
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
6156
|
+
}
|
|
6157
|
+
});
|
|
6158
|
+
}
|
|
6159
|
+
if (!await knex.schema.hasTable("statistics")) {
|
|
6160
|
+
console.log("[EXULU] Creating statistics table.");
|
|
6161
|
+
await knex.schema.createTable("statistics", (table) => {
|
|
6162
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
6163
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
6164
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
6165
|
+
for (const field of statisticsSchema.fields) {
|
|
6166
|
+
const { type, name, default: defaultValue } = field;
|
|
6167
|
+
if (!type || !name) {
|
|
6168
|
+
continue;
|
|
6169
|
+
}
|
|
6170
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
6171
|
+
}
|
|
6172
|
+
});
|
|
6173
|
+
}
|
|
6174
|
+
if (!await knex.schema.hasTable("jobs")) {
|
|
6175
|
+
console.log("[EXULU] Creating jobs table.");
|
|
6176
|
+
await knex.schema.createTable("jobs", (table) => {
|
|
6177
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
6178
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
6179
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
6180
|
+
for (const field of jobsSchema.fields) {
|
|
6181
|
+
const { type, name, default: defaultValue } = field;
|
|
6182
|
+
if (!type || !name) {
|
|
6183
|
+
continue;
|
|
6184
|
+
}
|
|
6185
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
6186
|
+
}
|
|
6187
|
+
});
|
|
6188
|
+
}
|
|
6189
|
+
if (!await knex.schema.hasTable("agents")) {
|
|
6190
|
+
console.log("[EXULU] Creating agents table.");
|
|
6191
|
+
await knex.schema.createTable("agents", (table) => {
|
|
6192
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
6193
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
6194
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
6195
|
+
for (const field of agentsSchema.fields) {
|
|
6196
|
+
const { type, name, default: defaultValue } = field;
|
|
6197
|
+
if (!type || !name) {
|
|
6198
|
+
continue;
|
|
6199
|
+
}
|
|
6200
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
6201
|
+
}
|
|
6202
|
+
});
|
|
6203
|
+
}
|
|
6204
|
+
if (!await knex.schema.hasTable("verification_token")) {
|
|
6205
|
+
console.log("[EXULU] Creating verification_token table.");
|
|
6206
|
+
await knex.schema.createTable("verification_token", (table) => {
|
|
6207
|
+
table.text("identifier").notNullable();
|
|
6208
|
+
table.timestamp("expires", { useTz: true }).notNullable();
|
|
6209
|
+
table.text("token").notNullable();
|
|
6210
|
+
table.primary(["identifier", "token"]);
|
|
6211
|
+
});
|
|
6212
|
+
}
|
|
6213
|
+
if (!await knex.schema.hasTable("users")) {
|
|
6214
|
+
console.log("[EXULU] Creating users table.");
|
|
6215
|
+
await knex.schema.createTable("users", (table) => {
|
|
6216
|
+
table.increments("id").primary();
|
|
6217
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
6218
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
6219
|
+
table.string("name", 255);
|
|
6220
|
+
table.string("password", 255);
|
|
6221
|
+
table.string("email", 255);
|
|
6222
|
+
table.timestamp("emailVerified", { useTz: true });
|
|
6223
|
+
table.text("image");
|
|
6224
|
+
for (const field of usersSchema.fields) {
|
|
6225
|
+
console.log("[EXULU] field", field);
|
|
6226
|
+
const { type, name, default: defaultValue } = field;
|
|
6227
|
+
if (name === "id" || name === "name" || name === "email" || name === "emailVerified" || name === "image") {
|
|
6228
|
+
continue;
|
|
6229
|
+
}
|
|
6230
|
+
if (!type || !name) {
|
|
6231
|
+
continue;
|
|
6232
|
+
}
|
|
6233
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
6234
|
+
}
|
|
6235
|
+
});
|
|
6236
|
+
}
|
|
6237
|
+
if (!await knex.schema.hasTable("accounts")) {
|
|
6238
|
+
console.log("[EXULU] Creating accounts table.");
|
|
6239
|
+
await knex.schema.createTable("accounts", (table) => {
|
|
6240
|
+
table.increments("id").primary();
|
|
6241
|
+
table.integer("userId").notNullable();
|
|
6242
|
+
table.string("type", 255).notNullable();
|
|
6243
|
+
table.string("provider", 255).notNullable();
|
|
6244
|
+
table.string("providerAccountId", 255).notNullable();
|
|
6245
|
+
table.text("refresh_token");
|
|
6246
|
+
table.text("access_token");
|
|
6247
|
+
table.bigInteger("expires_at");
|
|
6248
|
+
table.text("id_token");
|
|
6249
|
+
table.text("scope");
|
|
6250
|
+
table.text("session_state");
|
|
6251
|
+
table.text("token_type");
|
|
6252
|
+
});
|
|
6253
|
+
}
|
|
6254
|
+
};
|
|
6255
|
+
var execute = async () => {
|
|
6256
|
+
const { db: db3 } = await postgresClient();
|
|
6257
|
+
console.log("[EXULU] Checking Exulu IMP database status.");
|
|
6258
|
+
await up(db3);
|
|
6259
|
+
console.log("[EXULU] Inserting default user and admin role.");
|
|
6260
|
+
const existingRole = await db3.from("roles").where({ name: "admin" }).first();
|
|
6261
|
+
let roleId;
|
|
6262
|
+
if (!existingRole) {
|
|
6263
|
+
console.log("[EXULU] Creating default admin role.");
|
|
6264
|
+
const role = await db3.from("roles").insert({
|
|
6265
|
+
name: "admin",
|
|
6266
|
+
is_admin: true,
|
|
6267
|
+
agents: JSON.stringify([])
|
|
6268
|
+
}).returning("id");
|
|
6269
|
+
roleId = role[0].id;
|
|
6270
|
+
} else {
|
|
6271
|
+
roleId = existingRole.id;
|
|
6272
|
+
}
|
|
6273
|
+
const existingUser = await db3.from("users").where({ email: "admin@exulu.com" }).first();
|
|
6274
|
+
if (!existingUser) {
|
|
6275
|
+
const password = await encryptString("admin");
|
|
6276
|
+
console.log("[EXULU] Creating default admin user.");
|
|
6277
|
+
await db3.from("users").insert({
|
|
6278
|
+
name: "exulu",
|
|
6279
|
+
email: "admin@exulu.com",
|
|
6280
|
+
super_admin: true,
|
|
6281
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
6282
|
+
emailVerified: /* @__PURE__ */ new Date(),
|
|
6283
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
6284
|
+
password,
|
|
6285
|
+
type: "user",
|
|
6286
|
+
role: roleId
|
|
6287
|
+
});
|
|
6288
|
+
}
|
|
6289
|
+
const { key } = await generateApiKey("exulu", "api@exulu.com");
|
|
6290
|
+
console.log("[EXULU] Database initialized.");
|
|
6291
|
+
console.log("[EXULU] Default api key: ", `${key}`);
|
|
6292
|
+
console.log("[EXULU] Default password if using password auth: ", `admin`);
|
|
6293
|
+
console.log("[EXULU] Default email if using password auth: ", `admin@exulu.com`);
|
|
6294
|
+
return;
|
|
6295
|
+
};
|
|
6296
|
+
|
|
6275
6297
|
// src/index.ts
|
|
6276
6298
|
var ExuluJobs = {
|
|
6277
6299
|
redis: redisClient,
|
|
@@ -6279,6 +6301,11 @@ var ExuluJobs = {
|
|
|
6279
6301
|
validate: validateJob
|
|
6280
6302
|
}
|
|
6281
6303
|
};
|
|
6304
|
+
var db2 = {
|
|
6305
|
+
init: async () => {
|
|
6306
|
+
await execute();
|
|
6307
|
+
}
|
|
6308
|
+
};
|
|
6282
6309
|
var ExuluChunkers = {
|
|
6283
6310
|
sentence: SentenceChunker,
|
|
6284
6311
|
recursive: {
|
|
@@ -6303,5 +6330,6 @@ var ExuluChunkers = {
|
|
|
6303
6330
|
ExuluSource,
|
|
6304
6331
|
ExuluTool,
|
|
6305
6332
|
ExuluWorkflow,
|
|
6306
|
-
ExuluZodFileType
|
|
6333
|
+
ExuluZodFileType,
|
|
6334
|
+
db
|
|
6307
6335
|
});
|