@exulu/backend 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +335 -139
- package/dist/index.d.cts +62 -9
- package/dist/index.d.ts +62 -9
- package/dist/index.js +327 -132
- package/package.json +10 -9
- package/types/enums/jobs.ts +11 -0
package/dist/index.cjs
CHANGED
|
@@ -30,14 +30,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
EXULU_JOB_STATUS_ENUM: () => JOB_STATUS_ENUM,
|
|
33
34
|
EXULU_STATISTICS_TYPE_ENUM: () => STATISTICS_TYPE_ENUM,
|
|
34
35
|
ExuluAgent: () => ExuluAgent,
|
|
35
36
|
ExuluApp: () => ExuluApp,
|
|
36
37
|
ExuluAuthentication: () => authentication,
|
|
38
|
+
ExuluChunkers: () => ExuluChunkers,
|
|
37
39
|
ExuluContext: () => ExuluContext,
|
|
38
40
|
ExuluDatabase: () => ExuluDatabase,
|
|
39
41
|
ExuluEmbedder: () => ExuluEmbedder,
|
|
40
42
|
ExuluJobs: () => ExuluJobs,
|
|
43
|
+
ExuluLogger: () => ExuluLogger,
|
|
41
44
|
ExuluQueues: () => queues,
|
|
42
45
|
ExuluSource: () => ExuluSource,
|
|
43
46
|
ExuluTool: () => ExuluTool,
|
|
@@ -45,6 +48,7 @@ __export(index_exports, {
|
|
|
45
48
|
ExuluZodFileType: () => ExuluZodFileType
|
|
46
49
|
});
|
|
47
50
|
module.exports = __toCommonJS(index_exports);
|
|
51
|
+
var import_config = require("dotenv/config");
|
|
48
52
|
|
|
49
53
|
// src/redis/client.ts
|
|
50
54
|
var import_redis = require("redis");
|
|
@@ -155,6 +159,10 @@ var usersSchema = {
|
|
|
155
159
|
name: "firstname",
|
|
156
160
|
type: "text"
|
|
157
161
|
},
|
|
162
|
+
{
|
|
163
|
+
name: "name",
|
|
164
|
+
type: "text"
|
|
165
|
+
},
|
|
158
166
|
{
|
|
159
167
|
name: "lastname",
|
|
160
168
|
type: "text"
|
|
@@ -258,6 +266,70 @@ var statisticsSchema = {
|
|
|
258
266
|
}
|
|
259
267
|
]
|
|
260
268
|
};
|
|
269
|
+
var workflowSchema = {
|
|
270
|
+
name: {
|
|
271
|
+
plural: "workflows",
|
|
272
|
+
singular: "workflow"
|
|
273
|
+
},
|
|
274
|
+
fields: [
|
|
275
|
+
{
|
|
276
|
+
name: "workflow_name",
|
|
277
|
+
type: "text"
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
name: "run_id",
|
|
281
|
+
type: "text"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
name: "snapshot",
|
|
285
|
+
type: "text"
|
|
286
|
+
}
|
|
287
|
+
]
|
|
288
|
+
};
|
|
289
|
+
var threadsSchema = {
|
|
290
|
+
name: {
|
|
291
|
+
plural: "threads",
|
|
292
|
+
singular: "thread"
|
|
293
|
+
},
|
|
294
|
+
fields: [
|
|
295
|
+
{
|
|
296
|
+
name: "resourceId",
|
|
297
|
+
type: "text"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: "title",
|
|
301
|
+
type: "text"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
name: "metadata",
|
|
305
|
+
type: "text"
|
|
306
|
+
}
|
|
307
|
+
]
|
|
308
|
+
};
|
|
309
|
+
var messagesSchema = {
|
|
310
|
+
name: {
|
|
311
|
+
plural: "messages",
|
|
312
|
+
singular: "message"
|
|
313
|
+
},
|
|
314
|
+
fields: [
|
|
315
|
+
{
|
|
316
|
+
name: "thread_id",
|
|
317
|
+
type: "text"
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
name: "content",
|
|
321
|
+
type: "text"
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
name: "role",
|
|
325
|
+
type: "text"
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: "type",
|
|
329
|
+
type: "text"
|
|
330
|
+
}
|
|
331
|
+
]
|
|
332
|
+
};
|
|
261
333
|
var jobsSchema = {
|
|
262
334
|
name: {
|
|
263
335
|
plural: "jobs",
|
|
@@ -282,7 +354,7 @@ var jobsSchema = {
|
|
|
282
354
|
},
|
|
283
355
|
{
|
|
284
356
|
name: "result",
|
|
285
|
-
type: "
|
|
357
|
+
type: "longText"
|
|
286
358
|
},
|
|
287
359
|
{
|
|
288
360
|
name: "name",
|
|
@@ -292,6 +364,10 @@ var jobsSchema = {
|
|
|
292
364
|
name: "agent",
|
|
293
365
|
type: "text"
|
|
294
366
|
},
|
|
367
|
+
{
|
|
368
|
+
name: "workflow",
|
|
369
|
+
type: "text"
|
|
370
|
+
},
|
|
295
371
|
{
|
|
296
372
|
name: "user",
|
|
297
373
|
type: "text"
|
|
@@ -300,6 +376,10 @@ var jobsSchema = {
|
|
|
300
376
|
name: "item",
|
|
301
377
|
type: "text"
|
|
302
378
|
},
|
|
379
|
+
{
|
|
380
|
+
name: "steps",
|
|
381
|
+
type: "number"
|
|
382
|
+
},
|
|
303
383
|
{
|
|
304
384
|
name: "inputs",
|
|
305
385
|
type: "json"
|
|
@@ -403,14 +483,11 @@ var sanitizeName = (name) => {
|
|
|
403
483
|
return name.toLowerCase().replace(/ /g, "_");
|
|
404
484
|
};
|
|
405
485
|
|
|
406
|
-
// src/postgres/init-db.ts
|
|
407
|
-
var import_bcryptjs2 = __toESM(require("bcryptjs"), 1);
|
|
408
|
-
|
|
409
486
|
// src/auth/generate-key.ts
|
|
410
487
|
var import_bcryptjs = __toESM(require("bcryptjs"), 1);
|
|
411
488
|
var SALT_ROUNDS = 12;
|
|
412
|
-
async function
|
|
413
|
-
const hash = await import_bcryptjs.default.hash(
|
|
489
|
+
async function encryptString(string) {
|
|
490
|
+
const hash = await import_bcryptjs.default.hash(string, SALT_ROUNDS);
|
|
414
491
|
return hash;
|
|
415
492
|
}
|
|
416
493
|
var generateApiKey = async (name, email) => {
|
|
@@ -432,7 +509,7 @@ var generateApiKey = async (name, email) => {
|
|
|
432
509
|
const newKeyName = name;
|
|
433
510
|
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
434
511
|
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
435
|
-
const encryptedKey = await
|
|
512
|
+
const encryptedKey = await encryptString(plainKey);
|
|
436
513
|
const existingApiUser = await db2.from("users").where({ email }).first();
|
|
437
514
|
if (!existingApiUser) {
|
|
438
515
|
console.log("[EXULU] Creating default api user.");
|
|
@@ -443,6 +520,7 @@ var generateApiKey = async (name, email) => {
|
|
|
443
520
|
createdAt: /* @__PURE__ */ new Date(),
|
|
444
521
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
445
522
|
type: "api",
|
|
523
|
+
emailVerified: /* @__PURE__ */ new Date(),
|
|
446
524
|
apikey: `${encryptedKey}${postFix}`,
|
|
447
525
|
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
448
526
|
role: roleId
|
|
@@ -607,11 +685,6 @@ var up = async function(knex) {
|
|
|
607
685
|
});
|
|
608
686
|
}
|
|
609
687
|
};
|
|
610
|
-
var SALT_ROUNDS2 = 12;
|
|
611
|
-
async function encryptApiKey2(apikey) {
|
|
612
|
-
const hash = await import_bcryptjs2.default.hash(apikey, SALT_ROUNDS2);
|
|
613
|
-
return hash;
|
|
614
|
-
}
|
|
615
688
|
var execute = async () => {
|
|
616
689
|
console.log("[EXULU] Initializing database.");
|
|
617
690
|
const { db: db2 } = await postgresClient();
|
|
@@ -624,33 +697,33 @@ var execute = async () => {
|
|
|
624
697
|
const role = await db2.from("roles").insert({
|
|
625
698
|
name: "admin",
|
|
626
699
|
is_admin: true,
|
|
627
|
-
agents: []
|
|
700
|
+
agents: JSON.stringify([])
|
|
628
701
|
}).returning("id");
|
|
629
702
|
roleId = role[0].id;
|
|
630
703
|
} else {
|
|
631
704
|
roleId = existingRole.id;
|
|
632
705
|
}
|
|
633
|
-
const newKeyName = "exulu_default_key";
|
|
634
|
-
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
635
|
-
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
636
|
-
const encryptedKey = await encryptApiKey2(plainKey);
|
|
637
706
|
const existingUser = await db2.from("users").where({ email: "admin@exulu.com" }).first();
|
|
638
707
|
if (!existingUser) {
|
|
708
|
+
const password = await encryptString("admin");
|
|
639
709
|
console.log("[EXULU] Creating default admin user.");
|
|
640
710
|
await db2.from("users").insert({
|
|
641
711
|
name: "exulu",
|
|
642
712
|
email: "admin@exulu.com",
|
|
643
713
|
super_admin: true,
|
|
644
714
|
createdAt: /* @__PURE__ */ new Date(),
|
|
715
|
+
emailVerified: /* @__PURE__ */ new Date(),
|
|
645
716
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
717
|
+
password,
|
|
646
718
|
type: "user",
|
|
647
|
-
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
648
719
|
role: roleId
|
|
649
720
|
});
|
|
650
721
|
}
|
|
651
722
|
const { key } = await generateApiKey("exulu", "api@exulu.com");
|
|
652
723
|
console.log("[EXULU] Database initialized.");
|
|
653
724
|
console.log("[EXULU] Default api key: ", `${key}`);
|
|
725
|
+
console.log("[EXULU] Default password if using password auth: ", `admin`);
|
|
726
|
+
console.log("[EXULU] Default email if using password auth: ", `admin@exulu.com`);
|
|
654
727
|
return;
|
|
655
728
|
};
|
|
656
729
|
|
|
@@ -661,7 +734,6 @@ var import_core = require("@mastra/core");
|
|
|
661
734
|
var import_zod2 = require("zod");
|
|
662
735
|
var fs = __toESM(require("fs"), 1);
|
|
663
736
|
var path = __toESM(require("path"), 1);
|
|
664
|
-
var import_bullmq3 = require("bullmq");
|
|
665
737
|
var import_memory = require("@mastra/memory");
|
|
666
738
|
var import_pg = require("@mastra/pg");
|
|
667
739
|
|
|
@@ -697,6 +769,7 @@ var bullmqDecorator = async ({
|
|
|
697
769
|
configuration,
|
|
698
770
|
updater,
|
|
699
771
|
context,
|
|
772
|
+
steps,
|
|
700
773
|
source,
|
|
701
774
|
documents,
|
|
702
775
|
trigger,
|
|
@@ -714,11 +787,13 @@ var bullmqDecorator = async ({
|
|
|
714
787
|
...context && { context },
|
|
715
788
|
...source && { source },
|
|
716
789
|
...documents && { documents },
|
|
790
|
+
...steps && { steps },
|
|
717
791
|
...trigger && { trigger },
|
|
718
792
|
...item && { item },
|
|
719
793
|
agent,
|
|
720
794
|
user,
|
|
721
795
|
inputs,
|
|
796
|
+
label,
|
|
722
797
|
session
|
|
723
798
|
},
|
|
724
799
|
{
|
|
@@ -743,6 +818,7 @@ var bullmqDecorator = async ({
|
|
|
743
818
|
...embedder && { embedder },
|
|
744
819
|
...workflow && { workflow },
|
|
745
820
|
...configuration && { configuration },
|
|
821
|
+
...steps && { steps },
|
|
746
822
|
...updater && { updater },
|
|
747
823
|
...context && { context },
|
|
748
824
|
...source && { source },
|
|
@@ -766,6 +842,17 @@ var bullmqDecorator = async ({
|
|
|
766
842
|
};
|
|
767
843
|
};
|
|
768
844
|
|
|
845
|
+
// types/enums/jobs.ts
|
|
846
|
+
var JOB_STATUS_ENUM = {
|
|
847
|
+
completed: "completed",
|
|
848
|
+
failed: "failed",
|
|
849
|
+
delayed: "delayed",
|
|
850
|
+
active: "active",
|
|
851
|
+
waiting: "waiting",
|
|
852
|
+
paused: "paused",
|
|
853
|
+
stuck: "stuck"
|
|
854
|
+
};
|
|
855
|
+
|
|
769
856
|
// src/registry/classes.ts
|
|
770
857
|
function generateSlug(name) {
|
|
771
858
|
const normalized = name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "");
|
|
@@ -800,6 +887,7 @@ var ExuluAgent = class {
|
|
|
800
887
|
config;
|
|
801
888
|
memory;
|
|
802
889
|
tools;
|
|
890
|
+
agent;
|
|
803
891
|
capabilities;
|
|
804
892
|
constructor({ id, name, description, outputSchema, config, rateLimit, type, capabilities, tools }) {
|
|
805
893
|
this.id = id;
|
|
@@ -812,6 +900,14 @@ var ExuluAgent = class {
|
|
|
812
900
|
this.config = config;
|
|
813
901
|
this.capabilities = capabilities;
|
|
814
902
|
this.slug = `/agents/${generateSlug(this.name)}/run`;
|
|
903
|
+
if (this.type === "agent") {
|
|
904
|
+
this.agent = new import_core.Agent({
|
|
905
|
+
name: this.config.name,
|
|
906
|
+
instructions: this.config.instructions,
|
|
907
|
+
model: this.config.model,
|
|
908
|
+
memory: this.memory ? this.memory : void 0
|
|
909
|
+
});
|
|
910
|
+
}
|
|
815
911
|
if (config?.memory) {
|
|
816
912
|
console.log("[EXULU] Initializing memory for agent " + this.name);
|
|
817
913
|
const connectionString = `postgresql://${process.env.POSTGRES_DB_USER}:${process.env.POSTGRES_DB_PASSWORD}@${process.env.POSTGRES_DB_HOST}:${process.env.POSTGRES_DB_PORT}/exulu`;
|
|
@@ -825,7 +921,11 @@ var ExuluAgent = class {
|
|
|
825
921
|
password: process.env.POSTGRES_DB_PASSWORD || "",
|
|
826
922
|
ssl: process.env.POSTGRES_DB_SSL === "true" ? { rejectUnauthorized: false } : false
|
|
827
923
|
}),
|
|
828
|
-
...config?.memory.vector ? {
|
|
924
|
+
...config?.memory.vector ? {
|
|
925
|
+
vector: new import_pg.PgVector({
|
|
926
|
+
connectionString
|
|
927
|
+
})
|
|
928
|
+
} : {},
|
|
829
929
|
options: {
|
|
830
930
|
lastMessages: config?.memory.lastMessages || 10,
|
|
831
931
|
semanticRecall: {
|
|
@@ -836,33 +936,17 @@ var ExuluAgent = class {
|
|
|
836
936
|
});
|
|
837
937
|
}
|
|
838
938
|
}
|
|
839
|
-
chat =
|
|
840
|
-
|
|
841
|
-
const agent = await db2.from("agents").select("*").where("id", "=", id).first();
|
|
842
|
-
if (!agent) {
|
|
939
|
+
chat = () => {
|
|
940
|
+
if (!this.agent) {
|
|
843
941
|
throw new Error("Agent not found");
|
|
844
942
|
}
|
|
845
|
-
let tools = {};
|
|
846
|
-
agent.tools?.forEach(({ name }) => {
|
|
847
|
-
const tool = this.tools?.find((t) => t.name === name);
|
|
848
|
-
if (!tool) {
|
|
849
|
-
return;
|
|
850
|
-
}
|
|
851
|
-
return tool;
|
|
852
|
-
});
|
|
853
943
|
updateStatistic({
|
|
854
944
|
name: "count",
|
|
855
945
|
label: this.name,
|
|
856
946
|
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
857
947
|
trigger: "agent"
|
|
858
948
|
});
|
|
859
|
-
return
|
|
860
|
-
name: this.config.name,
|
|
861
|
-
instructions: this.config.instructions,
|
|
862
|
-
model: this.config.model,
|
|
863
|
-
tools,
|
|
864
|
-
memory: this.memory ? this.memory : void 0
|
|
865
|
-
});
|
|
949
|
+
return this.agent;
|
|
866
950
|
};
|
|
867
951
|
};
|
|
868
952
|
var ExuluEmbedder = class {
|
|
@@ -919,35 +1003,141 @@ var ExuluWorkflow = class {
|
|
|
919
1003
|
enable_batch = false;
|
|
920
1004
|
slug = "";
|
|
921
1005
|
queue;
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
constructor({ id, name, description, workflow, queue, enable_batch, inputSchema }) {
|
|
1006
|
+
steps;
|
|
1007
|
+
constructor({ id, name, description, steps, queue, enable_batch }) {
|
|
925
1008
|
this.id = id;
|
|
926
1009
|
this.name = name;
|
|
927
1010
|
this.description = description;
|
|
928
1011
|
this.enable_batch = enable_batch;
|
|
929
1012
|
this.slug = `/workflows/${generateSlug(this.name)}/run`;
|
|
930
1013
|
this.queue = queue;
|
|
931
|
-
this.
|
|
932
|
-
this.workflow = workflow;
|
|
1014
|
+
this.steps = steps;
|
|
933
1015
|
}
|
|
1016
|
+
start = async ({
|
|
1017
|
+
inputs: initialInputs,
|
|
1018
|
+
user,
|
|
1019
|
+
logger,
|
|
1020
|
+
job,
|
|
1021
|
+
session,
|
|
1022
|
+
agent,
|
|
1023
|
+
label
|
|
1024
|
+
}) => {
|
|
1025
|
+
let inputs;
|
|
1026
|
+
const { db: db2 } = await postgresClient();
|
|
1027
|
+
if (!job?.id) {
|
|
1028
|
+
logger.write(`Creating new job for workflow ${this.name} with inputs: ${JSON.stringify(initialInputs)}`, "INFO");
|
|
1029
|
+
const result = await db2("jobs").insert({
|
|
1030
|
+
status: JOB_STATUS_ENUM.active,
|
|
1031
|
+
name: `Job running '${this.name}' for '${label}'`,
|
|
1032
|
+
agent,
|
|
1033
|
+
workflow: this.id,
|
|
1034
|
+
type: "workflow",
|
|
1035
|
+
steps: this.steps?.length || 0,
|
|
1036
|
+
inputs: initialInputs,
|
|
1037
|
+
session,
|
|
1038
|
+
user
|
|
1039
|
+
}).returning(["id", "status"]);
|
|
1040
|
+
job = result[0];
|
|
1041
|
+
logger.write(`Created new job for workflow ${this.name}, job id: ${job?.id}`, "INFO");
|
|
1042
|
+
}
|
|
1043
|
+
if (!job) {
|
|
1044
|
+
throw new Error("Job not found, or failed to be created.");
|
|
1045
|
+
}
|
|
1046
|
+
if (job.status !== JOB_STATUS_ENUM.active) {
|
|
1047
|
+
await db2("jobs").update({
|
|
1048
|
+
status: JOB_STATUS_ENUM.active,
|
|
1049
|
+
inputs: initialInputs
|
|
1050
|
+
}).where({ id: job?.id }).returning("id");
|
|
1051
|
+
}
|
|
1052
|
+
const runStep = async (step, inputs2) => {
|
|
1053
|
+
let result;
|
|
1054
|
+
try {
|
|
1055
|
+
result = await step.fn({
|
|
1056
|
+
inputs: inputs2,
|
|
1057
|
+
logger,
|
|
1058
|
+
job,
|
|
1059
|
+
user
|
|
1060
|
+
});
|
|
1061
|
+
return result;
|
|
1062
|
+
} catch (error) {
|
|
1063
|
+
logger.write(`Step ${step.name} failed with error: ${error.message}`, "ERROR");
|
|
1064
|
+
if (step.retries && step.retries > 0) {
|
|
1065
|
+
logger.write(`Retrying step ${step.name} with ${step.retries} retries left`, "INFO");
|
|
1066
|
+
step.retries--;
|
|
1067
|
+
let result2 = await runStep(step, inputs2);
|
|
1068
|
+
return result2;
|
|
1069
|
+
}
|
|
1070
|
+
logger.write(`Step ${step.name} failed with error: ${error.message}`, "ERROR");
|
|
1071
|
+
throw error;
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
let final;
|
|
1075
|
+
try {
|
|
1076
|
+
for (let i = 0; i < this.steps.length; i++) {
|
|
1077
|
+
const step = this.steps[i];
|
|
1078
|
+
if (!step) {
|
|
1079
|
+
throw new Error("Step not found.");
|
|
1080
|
+
}
|
|
1081
|
+
if (i === 0) {
|
|
1082
|
+
inputs = initialInputs;
|
|
1083
|
+
}
|
|
1084
|
+
logger.write(`Running step ${step.name} with inputs: ${JSON.stringify(inputs)}`, "INFO");
|
|
1085
|
+
let result = await runStep(step, inputs);
|
|
1086
|
+
inputs = result;
|
|
1087
|
+
logger.write(`Step ${step.name} output: ${JSON.stringify(result)}`, "INFO");
|
|
1088
|
+
final = result;
|
|
1089
|
+
}
|
|
1090
|
+
await db2("jobs").update({
|
|
1091
|
+
status: JOB_STATUS_ENUM.completed,
|
|
1092
|
+
result: JSON.stringify(final),
|
|
1093
|
+
finished_at: db2.fn.now()
|
|
1094
|
+
}).where({ id: job?.id }).returning("id");
|
|
1095
|
+
return final;
|
|
1096
|
+
} catch (error) {
|
|
1097
|
+
logger.write(`Workflow ${this.name} failed with error: ${error.message} for job ${job?.id}`, "ERROR");
|
|
1098
|
+
await db2("jobs").update({
|
|
1099
|
+
status: JOB_STATUS_ENUM.failed,
|
|
1100
|
+
result: JSON.stringify({
|
|
1101
|
+
error: error.message || error,
|
|
1102
|
+
stack: error.stack || "No stack trace available"
|
|
1103
|
+
})
|
|
1104
|
+
}).where({ id: job?.id }).returning("id");
|
|
1105
|
+
throw error;
|
|
1106
|
+
}
|
|
1107
|
+
};
|
|
934
1108
|
};
|
|
935
1109
|
var ExuluLogger = class {
|
|
936
1110
|
logPath;
|
|
937
1111
|
job;
|
|
938
1112
|
constructor(job, logsDir) {
|
|
939
1113
|
this.job = job;
|
|
940
|
-
if (
|
|
941
|
-
fs.
|
|
1114
|
+
if (logsDir && job) {
|
|
1115
|
+
if (!fs.existsSync(logsDir)) {
|
|
1116
|
+
fs.mkdirSync(logsDir, { recursive: true });
|
|
1117
|
+
}
|
|
1118
|
+
this.logPath = path.join(logsDir, `${job.id}_${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.txt`);
|
|
942
1119
|
}
|
|
943
|
-
this.logPath = path.join(logsDir, `${job.id}_${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.txt`);
|
|
944
1120
|
}
|
|
945
1121
|
async write(message, level) {
|
|
946
1122
|
const logMessage = message.endsWith("\n") ? message : message + "\n";
|
|
1123
|
+
if (!this.logPath) {
|
|
1124
|
+
switch (level) {
|
|
1125
|
+
case "INFO":
|
|
1126
|
+
console.log(message);
|
|
1127
|
+
break;
|
|
1128
|
+
case "WARNING":
|
|
1129
|
+
console.warn(message);
|
|
1130
|
+
break;
|
|
1131
|
+
case "ERROR":
|
|
1132
|
+
console.error(message);
|
|
1133
|
+
break;
|
|
1134
|
+
}
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
947
1137
|
try {
|
|
948
1138
|
await fs.promises.appendFile(this.logPath, `[EXULU][${level}] - ${(/* @__PURE__ */ new Date()).toISOString()}: ${logMessage}`);
|
|
949
1139
|
} catch (error) {
|
|
950
|
-
console.error(`Error writing to log file ${this.job.id}:`, error);
|
|
1140
|
+
console.error(`Error writing to log file ${this.job ? this.job.id : "unknown job"}:`, error);
|
|
951
1141
|
throw error;
|
|
952
1142
|
}
|
|
953
1143
|
}
|
|
@@ -1510,7 +1700,7 @@ var import_express = require("express");
|
|
|
1510
1700
|
var import_jwt = require("next-auth/jwt");
|
|
1511
1701
|
|
|
1512
1702
|
// src/auth/auth.ts
|
|
1513
|
-
var
|
|
1703
|
+
var import_bcryptjs2 = __toESM(require("bcryptjs"), 1);
|
|
1514
1704
|
var authentication = async ({
|
|
1515
1705
|
apikey,
|
|
1516
1706
|
authtoken,
|
|
@@ -1603,16 +1793,14 @@ var authentication = async ({
|
|
|
1603
1793
|
code: 401
|
|
1604
1794
|
};
|
|
1605
1795
|
}
|
|
1606
|
-
console.log("[EXULU] users", users);
|
|
1607
1796
|
console.log("[EXULU] request_key_name", request_key_name);
|
|
1608
1797
|
console.log("[EXULU] request_key_compare_value", request_key_compare_value);
|
|
1609
1798
|
const filtered = users.filter(({ apikey: apikey2, id }) => apikey2.includes(request_key_name));
|
|
1610
|
-
console.log("[EXULU] filtered", filtered);
|
|
1611
1799
|
for (const user of filtered) {
|
|
1612
1800
|
const user_key_last_slash_index = user.apikey.lastIndexOf("/");
|
|
1613
1801
|
const user_key_compare_value = user.apikey.substring(0, user_key_last_slash_index);
|
|
1614
1802
|
console.log("[EXULU] user_key_compare_value", user_key_compare_value);
|
|
1615
|
-
const isMatch = await
|
|
1803
|
+
const isMatch = await import_bcryptjs2.default.compare(request_key_compare_value, user_key_compare_value);
|
|
1616
1804
|
console.log("[EXULU] isMatch", isMatch);
|
|
1617
1805
|
if (isMatch) {
|
|
1618
1806
|
await db2.from("users").where({ id: user.id }).update({
|
|
@@ -1796,7 +1984,7 @@ var requestValidators = {
|
|
|
1796
1984
|
var import_zodex = require("zodex");
|
|
1797
1985
|
|
|
1798
1986
|
// src/bullmq/queues.ts
|
|
1799
|
-
var
|
|
1987
|
+
var import_bullmq4 = require("bullmq");
|
|
1800
1988
|
var ExuluQueues = class {
|
|
1801
1989
|
queues;
|
|
1802
1990
|
constructor() {
|
|
@@ -1814,7 +2002,7 @@ var ExuluQueues = class {
|
|
|
1814
2002
|
console.error(`[EXULU] no redis server configured, but you are trying to use a queue ( ${name}), likely in an agent or workflow (look for ExuluQueues.use() ).`);
|
|
1815
2003
|
throw new Error(`[EXULU] no redis server configured.`);
|
|
1816
2004
|
}
|
|
1817
|
-
const newQueue = new
|
|
2005
|
+
const newQueue = new import_bullmq4.Queue(`${name}`, { connection: redisServer });
|
|
1818
2006
|
this.queues.push(newQueue);
|
|
1819
2007
|
return newQueue;
|
|
1820
2008
|
}
|
|
@@ -1834,6 +2022,7 @@ var VectorMethodEnum = {
|
|
|
1834
2022
|
// src/registry/routes.ts
|
|
1835
2023
|
var import_express4 = __toESM(require("express"), 1);
|
|
1836
2024
|
var import_server3 = require("@apollo/server");
|
|
2025
|
+
var Papa = __toESM(require("papaparse"), 1);
|
|
1837
2026
|
var import_cors = __toESM(require("cors"), 1);
|
|
1838
2027
|
var import_reflect_metadata = require("reflect-metadata");
|
|
1839
2028
|
|
|
@@ -2170,8 +2359,8 @@ var import_express5 = require("@as-integrations/express5");
|
|
|
2170
2359
|
|
|
2171
2360
|
// src/registry/uppy.ts
|
|
2172
2361
|
var import_express2 = require("express");
|
|
2362
|
+
var import_body_parser = __toESM(require("body-parser"), 1);
|
|
2173
2363
|
var import_jwt2 = require("next-auth/jwt");
|
|
2174
|
-
var bodyParser = require("body-parser");
|
|
2175
2364
|
var createUppyRoutes = async (app) => {
|
|
2176
2365
|
const {
|
|
2177
2366
|
S3Client,
|
|
@@ -2232,7 +2421,7 @@ var createUppyRoutes = async (app) => {
|
|
|
2232
2421
|
});
|
|
2233
2422
|
return stsClient;
|
|
2234
2423
|
}
|
|
2235
|
-
app.use(
|
|
2424
|
+
app.use(import_body_parser.default.urlencoded({ extended: true }), import_body_parser.default.json());
|
|
2236
2425
|
app.get("/s3/list", async (req, res, next) => {
|
|
2237
2426
|
const apikey = req.headers["exulu-api-key"] || null;
|
|
2238
2427
|
let authtoken = null;
|
|
@@ -2567,7 +2756,6 @@ var createUppyRoutes = async (app) => {
|
|
|
2567
2756
|
|
|
2568
2757
|
// src/registry/routes.ts
|
|
2569
2758
|
var import_utils = require("@apollo/utils.keyvaluecache");
|
|
2570
|
-
var Papa = require("papaparse");
|
|
2571
2759
|
var global_queues = {
|
|
2572
2760
|
logs_cleaner: "logs-cleaner"
|
|
2573
2761
|
};
|
|
@@ -2665,7 +2853,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2665
2853
|
} else {
|
|
2666
2854
|
console.log("===========================", "[EXULU] no redis server configured, not setting up recurring jobs.", "===========================");
|
|
2667
2855
|
}
|
|
2668
|
-
const schema = createSDL([usersSchema, rolesSchema, agentsSchema, jobsSchema]);
|
|
2856
|
+
const schema = createSDL([usersSchema, rolesSchema, agentsSchema, jobsSchema, workflowSchema, threadsSchema, messagesSchema]);
|
|
2669
2857
|
console.log("[EXULU] graphql server");
|
|
2670
2858
|
const server = new import_server3.ApolloServer({
|
|
2671
2859
|
cache: new import_utils.InMemoryLRUCache(),
|
|
@@ -2721,6 +2909,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2721
2909
|
description: agent.description,
|
|
2722
2910
|
active: agent.active,
|
|
2723
2911
|
public: agent.public,
|
|
2912
|
+
type: agent.type,
|
|
2724
2913
|
slug: backend?.slug,
|
|
2725
2914
|
rateLimit: backend?.rateLimit,
|
|
2726
2915
|
streaming: backend?.streaming,
|
|
@@ -2930,21 +3119,27 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2930
3119
|
}
|
|
2931
3120
|
const context = contexts.find((context2) => context2.id === req.params.context);
|
|
2932
3121
|
if (!context) {
|
|
3122
|
+
console.error("[EXULU] context not found in registry.", req.params.context);
|
|
2933
3123
|
res.status(400).json({
|
|
2934
3124
|
message: "Context not found in registry."
|
|
2935
3125
|
});
|
|
2936
3126
|
return;
|
|
2937
3127
|
}
|
|
3128
|
+
console.log("[EXULU] context", context);
|
|
2938
3129
|
const exists = await context.tableExists();
|
|
2939
3130
|
if (!exists) {
|
|
3131
|
+
console.log("[EXULU] context table does not exist, creating it.");
|
|
2940
3132
|
await context.createItemsTable();
|
|
2941
3133
|
}
|
|
3134
|
+
console.log("[EXULU] inserting item", req.body);
|
|
2942
3135
|
const result = await context.insertItem(authenticationResult.user.id, req.body, !!req.body.upsert);
|
|
3136
|
+
console.log("[EXULU] result", result);
|
|
2943
3137
|
res.status(200).json({
|
|
2944
3138
|
message: "Item created successfully.",
|
|
2945
3139
|
id: result
|
|
2946
3140
|
});
|
|
2947
3141
|
} catch (error) {
|
|
3142
|
+
console.error("[EXULU] error upserting item", error);
|
|
2948
3143
|
res.status(500).json({
|
|
2949
3144
|
message: error?.message || "An error occurred while creating the item."
|
|
2950
3145
|
});
|
|
@@ -3289,7 +3484,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3289
3484
|
slug: workflow.slug,
|
|
3290
3485
|
enable_batch: workflow.enable_batch,
|
|
3291
3486
|
queue: workflow.queue?.name,
|
|
3292
|
-
inputSchema: workflow.inputSchema ? (0, import_zodex.zerialize)(workflow.inputSchema) : null
|
|
3487
|
+
inputSchema: workflow.steps[0]?.inputSchema ? (0, import_zodex.zerialize)(workflow.steps[0].inputSchema) : null
|
|
3293
3488
|
})));
|
|
3294
3489
|
});
|
|
3295
3490
|
console.log("[EXULU] workflow by id");
|
|
@@ -3316,7 +3511,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3316
3511
|
res.status(200).json({
|
|
3317
3512
|
...workflow,
|
|
3318
3513
|
queue: workflow.queue?.name,
|
|
3319
|
-
inputSchema: workflow.inputSchema ? (0, import_zodex.zerialize)(workflow.inputSchema) : null,
|
|
3514
|
+
inputSchema: workflow.steps[0]?.inputSchema ? (0, import_zodex.zerialize)(workflow.steps[0].inputSchema) : null,
|
|
3320
3515
|
workflow: void 0
|
|
3321
3516
|
});
|
|
3322
3517
|
});
|
|
@@ -3452,10 +3647,6 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3452
3647
|
note: `Execute workflow ${workflow.name}`
|
|
3453
3648
|
});
|
|
3454
3649
|
app.post(`${workflow.slug}`, async (req, res) => {
|
|
3455
|
-
if (!workflow.queue) {
|
|
3456
|
-
res.status(500).json({ detail: "No queue set for workflow." });
|
|
3457
|
-
return;
|
|
3458
|
-
}
|
|
3459
3650
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
3460
3651
|
if (!authenticationResult.user?.id) {
|
|
3461
3652
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
@@ -3472,6 +3663,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3472
3663
|
label: `Job running '${workflow.name}' for '${req.body.label}'`,
|
|
3473
3664
|
agent: req.body.agent,
|
|
3474
3665
|
workflow: workflow.id,
|
|
3666
|
+
steps: workflow.steps?.length || 0,
|
|
3475
3667
|
type: "workflow",
|
|
3476
3668
|
inputs,
|
|
3477
3669
|
session: req.body.session,
|
|
@@ -3490,22 +3682,19 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3490
3682
|
});
|
|
3491
3683
|
return;
|
|
3492
3684
|
}
|
|
3493
|
-
const { runId, start, watch } = workflow.workflow.createRun();
|
|
3494
3685
|
console.log("[EXULU] running workflow with inputs.", inputs);
|
|
3495
|
-
const
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3686
|
+
const logger = new ExuluLogger();
|
|
3687
|
+
const result = await workflow.start({
|
|
3688
|
+
inputs,
|
|
3689
|
+
user: authenticationResult.user.id,
|
|
3690
|
+
logger,
|
|
3691
|
+
session: req.body.session,
|
|
3692
|
+
agent: req.body.agent,
|
|
3693
|
+
label: req.body.label
|
|
3500
3694
|
});
|
|
3501
|
-
const failedSteps = Object.entries(output.results).filter(([_, step]) => step.status === "failed").map(([id, step]) => `${id}: ${step.error}`);
|
|
3502
|
-
if (failedSteps.length > 0) {
|
|
3503
|
-
const message = `Workflow has failed steps: ${failedSteps.join("\n - ")}`;
|
|
3504
|
-
throw new Error(message);
|
|
3505
|
-
}
|
|
3506
3695
|
res.status(200).json({
|
|
3507
3696
|
"job": {},
|
|
3508
|
-
"output":
|
|
3697
|
+
"output": result
|
|
3509
3698
|
});
|
|
3510
3699
|
return;
|
|
3511
3700
|
});
|
|
@@ -3563,48 +3752,45 @@ var getPresignedFileUrl = async (key) => {
|
|
|
3563
3752
|
|
|
3564
3753
|
// src/registry/workers.ts
|
|
3565
3754
|
var import_ioredis = __toESM(require("ioredis"), 1);
|
|
3566
|
-
var
|
|
3755
|
+
var import_bullmq7 = require("bullmq");
|
|
3567
3756
|
|
|
3568
3757
|
// src/registry/utils.ts
|
|
3569
|
-
var
|
|
3758
|
+
var import_bullmq6 = require("bullmq");
|
|
3570
3759
|
var bullmq = {
|
|
3571
|
-
validate: (
|
|
3572
|
-
if (!
|
|
3573
|
-
throw new Error(`Missing job data for job ${
|
|
3760
|
+
validate: (bullmqJob) => {
|
|
3761
|
+
if (!bullmqJob.data) {
|
|
3762
|
+
throw new Error(`Missing job data for job ${bullmqJob.id}.`);
|
|
3574
3763
|
}
|
|
3575
|
-
if (!
|
|
3576
|
-
throw new Error(`Missing property "type" in data for job ${
|
|
3764
|
+
if (!bullmqJob.data.type) {
|
|
3765
|
+
throw new Error(`Missing property "type" in data for job ${bullmqJob.id}.`);
|
|
3577
3766
|
}
|
|
3578
|
-
if (!
|
|
3579
|
-
throw new Error(`Missing property "inputs" in data for job ${
|
|
3767
|
+
if (!bullmqJob.data.inputs) {
|
|
3768
|
+
throw new Error(`Missing property "inputs" in data for job ${bullmqJob.id}.`);
|
|
3580
3769
|
}
|
|
3581
|
-
if (
|
|
3582
|
-
throw new Error(`Property "type" in data for job ${
|
|
3770
|
+
if (bullmqJob.data.type !== "embedder" && bullmqJob.data.type !== "workflow") {
|
|
3771
|
+
throw new Error(`Property "type" in data for job ${bullmqJob.id} must be of value "embedder" or "workflow".`);
|
|
3583
3772
|
}
|
|
3584
|
-
if (!
|
|
3585
|
-
throw new Error(`Property "backend" in data for job ${
|
|
3773
|
+
if (!bullmqJob.data.workflow && !bullmqJob.data.embedder) {
|
|
3774
|
+
throw new Error(`Property "backend" in data for job ${bullmqJob.id} missing. Job data: ${JSON.stringify(bullmqJob)}`);
|
|
3586
3775
|
}
|
|
3587
3776
|
},
|
|
3588
3777
|
process: {
|
|
3589
|
-
workflow: async (
|
|
3778
|
+
workflow: async (bullmqJob, exuluJob, workflow, logsDir) => {
|
|
3590
3779
|
if (!workflow) {
|
|
3591
|
-
throw new Error(`Workflow function with id: ${
|
|
3592
|
-
}
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
const
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
logger
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
throw new Error(message);
|
|
3606
|
-
}
|
|
3607
|
-
await logger.write(`Workflow completed. ${JSON.stringify(output.results)}`, "INFO");
|
|
3780
|
+
throw new Error(`Workflow function with id: ${bullmqJob.data.backend} not found in registry.`);
|
|
3781
|
+
}
|
|
3782
|
+
console.log("[EXULU] starting workflow with job inputs.", bullmqJob.data.inputs);
|
|
3783
|
+
const logger = new ExuluLogger(exuluJob, logsDir);
|
|
3784
|
+
const output = await workflow.start({
|
|
3785
|
+
job: exuluJob,
|
|
3786
|
+
inputs: bullmqJob.data.inputs,
|
|
3787
|
+
user: bullmqJob.data.user,
|
|
3788
|
+
logger,
|
|
3789
|
+
session: bullmqJob.data.session,
|
|
3790
|
+
agent: bullmqJob.data.agent,
|
|
3791
|
+
label: bullmqJob.data.label
|
|
3792
|
+
});
|
|
3793
|
+
await logger.write(`Workflow completed. ${JSON.stringify(output)}`, "INFO");
|
|
3608
3794
|
return output;
|
|
3609
3795
|
}
|
|
3610
3796
|
}
|
|
@@ -3629,58 +3815,58 @@ var createWorkers = async (queues2, contexts, embedders, workflows, _logsDir) =>
|
|
|
3629
3815
|
const logsDir = _logsDir || defaultLogsDir;
|
|
3630
3816
|
const workers = queues2.map((queue) => {
|
|
3631
3817
|
console.log(`[EXULU] creating worker for queue ${queue}.`);
|
|
3632
|
-
const worker = new
|
|
3818
|
+
const worker = new import_bullmq7.Worker(
|
|
3633
3819
|
`${queue}`,
|
|
3634
|
-
async (
|
|
3820
|
+
async (bullmqJob) => {
|
|
3635
3821
|
const { db: db2 } = await postgresClient();
|
|
3636
3822
|
try {
|
|
3637
|
-
bullmq.validate(
|
|
3638
|
-
if (
|
|
3639
|
-
if (!
|
|
3823
|
+
bullmq.validate(bullmqJob);
|
|
3824
|
+
if (bullmqJob.data.type === "embedder") {
|
|
3825
|
+
if (!bullmqJob.data.updater) {
|
|
3640
3826
|
throw new Error("No updater set for embedder job.");
|
|
3641
3827
|
}
|
|
3642
|
-
const context = contexts.find((context2) => context2.id ===
|
|
3828
|
+
const context = contexts.find((context2) => context2.id === bullmqJob.data.context);
|
|
3643
3829
|
if (!context) {
|
|
3644
|
-
throw new Error(`Context ${
|
|
3830
|
+
throw new Error(`Context ${bullmqJob.data.context} not found in the registry.`);
|
|
3645
3831
|
}
|
|
3646
|
-
if (!
|
|
3832
|
+
if (!bullmqJob.data.embedder) {
|
|
3647
3833
|
throw new Error(`No embedder set for embedder job.`);
|
|
3648
3834
|
}
|
|
3649
|
-
const embedder = embedders.find((embedder2) => embedder2.id ===
|
|
3835
|
+
const embedder = embedders.find((embedder2) => embedder2.id === bullmqJob.data.embedder);
|
|
3650
3836
|
if (!embedder) {
|
|
3651
|
-
throw new Error(`Embedder ${
|
|
3837
|
+
throw new Error(`Embedder ${bullmqJob.data.embedder} not found in the registry.`);
|
|
3652
3838
|
}
|
|
3653
|
-
if (!
|
|
3839
|
+
if (!bullmqJob.data.source) {
|
|
3654
3840
|
throw new Error("No source set for embedder job.");
|
|
3655
3841
|
}
|
|
3656
|
-
const source = context.sources.get(
|
|
3842
|
+
const source = context.sources.get(bullmqJob.data.source);
|
|
3657
3843
|
if (!source) {
|
|
3658
|
-
throw new Error(`Source ${
|
|
3844
|
+
throw new Error(`Source ${bullmqJob.data.source} not found in the registry.`);
|
|
3659
3845
|
}
|
|
3660
|
-
if (!
|
|
3846
|
+
if (!bullmqJob.data.updater) {
|
|
3661
3847
|
throw new Error("No updater set for embedder job.");
|
|
3662
3848
|
}
|
|
3663
|
-
const updater = source.updaters.find((updater2) => updater2.id ===
|
|
3849
|
+
const updater = source.updaters.find((updater2) => updater2.id === bullmqJob.data.updater);
|
|
3664
3850
|
if (!updater) {
|
|
3665
|
-
throw new Error(`Updater ${
|
|
3851
|
+
throw new Error(`Updater ${bullmqJob.data.updater} not found in the registry.`);
|
|
3666
3852
|
}
|
|
3667
|
-
if (!
|
|
3853
|
+
if (!bullmqJob.data.documents) {
|
|
3668
3854
|
throw new Error("No input documents set for embedder job.");
|
|
3669
3855
|
}
|
|
3670
|
-
if (!Array.isArray(
|
|
3856
|
+
if (!Array.isArray(bullmqJob.data.documents)) {
|
|
3671
3857
|
throw new Error("Input documents must be an array.");
|
|
3672
3858
|
}
|
|
3673
|
-
const result = await embedder.upsert(
|
|
3859
|
+
const result = await embedder.upsert(bullmqJob.data.context, bullmqJob.data.documents, {
|
|
3674
3860
|
label: context.name,
|
|
3675
|
-
trigger:
|
|
3861
|
+
trigger: bullmqJob.data.trigger || "unknown"
|
|
3676
3862
|
});
|
|
3677
|
-
const mongoRecord = await db2.from("jobs").where({ redis:
|
|
3863
|
+
const mongoRecord = await db2.from("jobs").where({ redis: bullmqJob.id }).first();
|
|
3678
3864
|
if (!mongoRecord) {
|
|
3679
3865
|
throw new Error("Job not found in the database.");
|
|
3680
3866
|
}
|
|
3681
3867
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
3682
3868
|
const duration = (finishedAt.getTime() - new Date(mongoRecord.createdAt).getTime()) / 1e3;
|
|
3683
|
-
await db2.from("jobs").where({ redis:
|
|
3869
|
+
await db2.from("jobs").where({ redis: bullmqJob.id }).update({
|
|
3684
3870
|
status: "completed",
|
|
3685
3871
|
finishedAt,
|
|
3686
3872
|
duration,
|
|
@@ -3688,19 +3874,19 @@ var createWorkers = async (queues2, contexts, embedders, workflows, _logsDir) =>
|
|
|
3688
3874
|
});
|
|
3689
3875
|
return result;
|
|
3690
3876
|
}
|
|
3691
|
-
if (
|
|
3692
|
-
const workflow = workflows.find((workflow2) => workflow2.id ===
|
|
3877
|
+
if (bullmqJob.data.type === "workflow") {
|
|
3878
|
+
const workflow = workflows.find((workflow2) => workflow2.id === bullmqJob.data.workflow);
|
|
3693
3879
|
if (!workflow) {
|
|
3694
|
-
throw new Error(`Workflow ${
|
|
3880
|
+
throw new Error(`Workflow ${bullmqJob.data.workflow} not found in the registry.`);
|
|
3695
3881
|
}
|
|
3696
|
-
const
|
|
3697
|
-
|
|
3698
|
-
if (!mongoRecord) {
|
|
3882
|
+
const exuluJob = await db2.from("jobs").where({ redis: bullmqJob.id }).first();
|
|
3883
|
+
if (!exuluJob) {
|
|
3699
3884
|
throw new Error("Job not found in the database.");
|
|
3700
3885
|
}
|
|
3886
|
+
const result = await bullmq.process.workflow(bullmqJob, exuluJob, workflow, logsDir);
|
|
3701
3887
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
3702
|
-
const duration = (finishedAt.getTime() - new Date(
|
|
3703
|
-
await db2.from("jobs").where({ redis:
|
|
3888
|
+
const duration = (finishedAt.getTime() - new Date(exuluJob.createdAt).getTime()) / 1e3;
|
|
3889
|
+
await db2.from("jobs").where({ redis: bullmqJob.id }).update({
|
|
3704
3890
|
status: "completed",
|
|
3705
3891
|
finishedAt,
|
|
3706
3892
|
duration,
|
|
@@ -3709,7 +3895,7 @@ var createWorkers = async (queues2, contexts, embedders, workflows, _logsDir) =>
|
|
|
3709
3895
|
return result;
|
|
3710
3896
|
}
|
|
3711
3897
|
} catch (error) {
|
|
3712
|
-
await db2.from("jobs").where({ redis:
|
|
3898
|
+
await db2.from("jobs").where({ redis: bullmqJob.id }).update({
|
|
3713
3899
|
status: "failed",
|
|
3714
3900
|
finishedAt: /* @__PURE__ */ new Date(),
|
|
3715
3901
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -3738,7 +3924,7 @@ var createWorkers = async (queues2, contexts, embedders, workflows, _logsDir) =>
|
|
|
3738
3924
|
return workers;
|
|
3739
3925
|
};
|
|
3740
3926
|
var createLogsCleanerWorker = (logsDir) => {
|
|
3741
|
-
const logsCleaner = new
|
|
3927
|
+
const logsCleaner = new import_bullmq7.Worker(
|
|
3742
3928
|
global_queues.logs_cleaner,
|
|
3743
3929
|
async (job) => {
|
|
3744
3930
|
console.log(`[EXULU] recurring job ${job.id}.`);
|
|
@@ -3851,12 +4037,19 @@ var ExuluApp = class {
|
|
|
3851
4037
|
};
|
|
3852
4038
|
|
|
3853
4039
|
// src/index.ts
|
|
4040
|
+
var import_chonkie = require("chonkie");
|
|
3854
4041
|
var ExuluJobs = {
|
|
3855
4042
|
redis: redisClient,
|
|
3856
4043
|
jobs: {
|
|
3857
4044
|
validate: validateJob
|
|
3858
4045
|
}
|
|
3859
4046
|
};
|
|
4047
|
+
var ExuluChunkers = {
|
|
4048
|
+
chonkie: {
|
|
4049
|
+
sentence: import_chonkie.SentenceChunker,
|
|
4050
|
+
recursive: import_chonkie.RecursiveChunker
|
|
4051
|
+
}
|
|
4052
|
+
};
|
|
3860
4053
|
var ExuluDatabase = {
|
|
3861
4054
|
init: async () => {
|
|
3862
4055
|
await execute();
|
|
@@ -3867,14 +4060,17 @@ var ExuluDatabase = {
|
|
|
3867
4060
|
};
|
|
3868
4061
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3869
4062
|
0 && (module.exports = {
|
|
4063
|
+
EXULU_JOB_STATUS_ENUM,
|
|
3870
4064
|
EXULU_STATISTICS_TYPE_ENUM,
|
|
3871
4065
|
ExuluAgent,
|
|
3872
4066
|
ExuluApp,
|
|
3873
4067
|
ExuluAuthentication,
|
|
4068
|
+
ExuluChunkers,
|
|
3874
4069
|
ExuluContext,
|
|
3875
4070
|
ExuluDatabase,
|
|
3876
4071
|
ExuluEmbedder,
|
|
3877
4072
|
ExuluJobs,
|
|
4073
|
+
ExuluLogger,
|
|
3878
4074
|
ExuluQueues,
|
|
3879
4075
|
ExuluSource,
|
|
3880
4076
|
ExuluTool,
|