@exulu/backend 0.2.2 → 0.2.4
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 +346 -142
- package/dist/index.d.cts +61 -9
- package/dist/index.d.ts +61 -9
- package/dist/index.js +338 -135
- 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,
|
|
@@ -2778,13 +2967,22 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2778
2967
|
if (!exists) {
|
|
2779
2968
|
throw new Error("Table with name " + context.getTableName() + " does not exist.");
|
|
2780
2969
|
}
|
|
2781
|
-
const
|
|
2970
|
+
const query = db2.from(context.getTableName()).select("id");
|
|
2782
2971
|
if (id) {
|
|
2783
|
-
|
|
2972
|
+
query.where({ id });
|
|
2784
2973
|
}
|
|
2785
2974
|
if (external_id) {
|
|
2786
|
-
|
|
2975
|
+
query.where({ external_id });
|
|
2787
2976
|
}
|
|
2977
|
+
const item = await query.first();
|
|
2978
|
+
if (!item) {
|
|
2979
|
+
throw new Error("Item not found.");
|
|
2980
|
+
}
|
|
2981
|
+
const chunks = await db2.from(context.getChunksTableName()).where({ source: item.id }).select("id");
|
|
2982
|
+
if (chunks.length > 0) {
|
|
2983
|
+
await db2.from(context.getChunksTableName()).where({ source: item.id }).delete();
|
|
2984
|
+
}
|
|
2985
|
+
const mutation = db2.from(context.getTableName()).where({ id: item.id }).delete().returning("id");
|
|
2788
2986
|
const result = await mutation;
|
|
2789
2987
|
return result;
|
|
2790
2988
|
};
|
|
@@ -2921,21 +3119,27 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2921
3119
|
}
|
|
2922
3120
|
const context = contexts.find((context2) => context2.id === req.params.context);
|
|
2923
3121
|
if (!context) {
|
|
3122
|
+
console.error("[EXULU] context not found in registry.", req.params.context);
|
|
2924
3123
|
res.status(400).json({
|
|
2925
3124
|
message: "Context not found in registry."
|
|
2926
3125
|
});
|
|
2927
3126
|
return;
|
|
2928
3127
|
}
|
|
3128
|
+
console.log("[EXULU] context", context);
|
|
2929
3129
|
const exists = await context.tableExists();
|
|
2930
3130
|
if (!exists) {
|
|
3131
|
+
console.log("[EXULU] context table does not exist, creating it.");
|
|
2931
3132
|
await context.createItemsTable();
|
|
2932
3133
|
}
|
|
3134
|
+
console.log("[EXULU] inserting item", req.body);
|
|
2933
3135
|
const result = await context.insertItem(authenticationResult.user.id, req.body, !!req.body.upsert);
|
|
3136
|
+
console.log("[EXULU] result", result);
|
|
2934
3137
|
res.status(200).json({
|
|
2935
3138
|
message: "Item created successfully.",
|
|
2936
3139
|
id: result
|
|
2937
3140
|
});
|
|
2938
3141
|
} catch (error) {
|
|
3142
|
+
console.error("[EXULU] error upserting item", error);
|
|
2939
3143
|
res.status(500).json({
|
|
2940
3144
|
message: error?.message || "An error occurred while creating the item."
|
|
2941
3145
|
});
|
|
@@ -3280,7 +3484,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3280
3484
|
slug: workflow.slug,
|
|
3281
3485
|
enable_batch: workflow.enable_batch,
|
|
3282
3486
|
queue: workflow.queue?.name,
|
|
3283
|
-
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
|
|
3284
3488
|
})));
|
|
3285
3489
|
});
|
|
3286
3490
|
console.log("[EXULU] workflow by id");
|
|
@@ -3307,7 +3511,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3307
3511
|
res.status(200).json({
|
|
3308
3512
|
...workflow,
|
|
3309
3513
|
queue: workflow.queue?.name,
|
|
3310
|
-
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,
|
|
3311
3515
|
workflow: void 0
|
|
3312
3516
|
});
|
|
3313
3517
|
});
|
|
@@ -3443,10 +3647,6 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3443
3647
|
note: `Execute workflow ${workflow.name}`
|
|
3444
3648
|
});
|
|
3445
3649
|
app.post(`${workflow.slug}`, async (req, res) => {
|
|
3446
|
-
if (!workflow.queue) {
|
|
3447
|
-
res.status(500).json({ detail: "No queue set for workflow." });
|
|
3448
|
-
return;
|
|
3449
|
-
}
|
|
3450
3650
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
3451
3651
|
if (!authenticationResult.user?.id) {
|
|
3452
3652
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
@@ -3463,6 +3663,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3463
3663
|
label: `Job running '${workflow.name}' for '${req.body.label}'`,
|
|
3464
3664
|
agent: req.body.agent,
|
|
3465
3665
|
workflow: workflow.id,
|
|
3666
|
+
steps: workflow.steps?.length || 0,
|
|
3466
3667
|
type: "workflow",
|
|
3467
3668
|
inputs,
|
|
3468
3669
|
session: req.body.session,
|
|
@@ -3481,22 +3682,19 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3481
3682
|
});
|
|
3482
3683
|
return;
|
|
3483
3684
|
}
|
|
3484
|
-
const { runId, start, watch } = workflow.workflow.createRun();
|
|
3485
3685
|
console.log("[EXULU] running workflow with inputs.", inputs);
|
|
3486
|
-
const
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
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
|
|
3491
3694
|
});
|
|
3492
|
-
const failedSteps = Object.entries(output.results).filter(([_, step]) => step.status === "failed").map(([id, step]) => `${id}: ${step.error}`);
|
|
3493
|
-
if (failedSteps.length > 0) {
|
|
3494
|
-
const message = `Workflow has failed steps: ${failedSteps.join("\n - ")}`;
|
|
3495
|
-
throw new Error(message);
|
|
3496
|
-
}
|
|
3497
3695
|
res.status(200).json({
|
|
3498
3696
|
"job": {},
|
|
3499
|
-
"output":
|
|
3697
|
+
"output": result
|
|
3500
3698
|
});
|
|
3501
3699
|
return;
|
|
3502
3700
|
});
|
|
@@ -3554,48 +3752,45 @@ var getPresignedFileUrl = async (key) => {
|
|
|
3554
3752
|
|
|
3555
3753
|
// src/registry/workers.ts
|
|
3556
3754
|
var import_ioredis = __toESM(require("ioredis"), 1);
|
|
3557
|
-
var
|
|
3755
|
+
var import_bullmq7 = require("bullmq");
|
|
3558
3756
|
|
|
3559
3757
|
// src/registry/utils.ts
|
|
3560
|
-
var
|
|
3758
|
+
var import_bullmq6 = require("bullmq");
|
|
3561
3759
|
var bullmq = {
|
|
3562
|
-
validate: (
|
|
3563
|
-
if (!
|
|
3564
|
-
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}.`);
|
|
3565
3763
|
}
|
|
3566
|
-
if (!
|
|
3567
|
-
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}.`);
|
|
3568
3766
|
}
|
|
3569
|
-
if (!
|
|
3570
|
-
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}.`);
|
|
3571
3769
|
}
|
|
3572
|
-
if (
|
|
3573
|
-
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".`);
|
|
3574
3772
|
}
|
|
3575
|
-
if (!
|
|
3576
|
-
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)}`);
|
|
3577
3775
|
}
|
|
3578
3776
|
},
|
|
3579
3777
|
process: {
|
|
3580
|
-
workflow: async (
|
|
3778
|
+
workflow: async (bullmqJob, exuluJob, workflow, logsDir) => {
|
|
3581
3779
|
if (!workflow) {
|
|
3582
|
-
throw new Error(`Workflow function with id: ${
|
|
3583
|
-
}
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
const
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
logger
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
throw new Error(message);
|
|
3597
|
-
}
|
|
3598
|
-
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");
|
|
3599
3794
|
return output;
|
|
3600
3795
|
}
|
|
3601
3796
|
}
|
|
@@ -3620,58 +3815,58 @@ var createWorkers = async (queues2, contexts, embedders, workflows, _logsDir) =>
|
|
|
3620
3815
|
const logsDir = _logsDir || defaultLogsDir;
|
|
3621
3816
|
const workers = queues2.map((queue) => {
|
|
3622
3817
|
console.log(`[EXULU] creating worker for queue ${queue}.`);
|
|
3623
|
-
const worker = new
|
|
3818
|
+
const worker = new import_bullmq7.Worker(
|
|
3624
3819
|
`${queue}`,
|
|
3625
|
-
async (
|
|
3820
|
+
async (bullmqJob) => {
|
|
3626
3821
|
const { db: db2 } = await postgresClient();
|
|
3627
3822
|
try {
|
|
3628
|
-
bullmq.validate(
|
|
3629
|
-
if (
|
|
3630
|
-
if (!
|
|
3823
|
+
bullmq.validate(bullmqJob);
|
|
3824
|
+
if (bullmqJob.data.type === "embedder") {
|
|
3825
|
+
if (!bullmqJob.data.updater) {
|
|
3631
3826
|
throw new Error("No updater set for embedder job.");
|
|
3632
3827
|
}
|
|
3633
|
-
const context = contexts.find((context2) => context2.id ===
|
|
3828
|
+
const context = contexts.find((context2) => context2.id === bullmqJob.data.context);
|
|
3634
3829
|
if (!context) {
|
|
3635
|
-
throw new Error(`Context ${
|
|
3830
|
+
throw new Error(`Context ${bullmqJob.data.context} not found in the registry.`);
|
|
3636
3831
|
}
|
|
3637
|
-
if (!
|
|
3832
|
+
if (!bullmqJob.data.embedder) {
|
|
3638
3833
|
throw new Error(`No embedder set for embedder job.`);
|
|
3639
3834
|
}
|
|
3640
|
-
const embedder = embedders.find((embedder2) => embedder2.id ===
|
|
3835
|
+
const embedder = embedders.find((embedder2) => embedder2.id === bullmqJob.data.embedder);
|
|
3641
3836
|
if (!embedder) {
|
|
3642
|
-
throw new Error(`Embedder ${
|
|
3837
|
+
throw new Error(`Embedder ${bullmqJob.data.embedder} not found in the registry.`);
|
|
3643
3838
|
}
|
|
3644
|
-
if (!
|
|
3839
|
+
if (!bullmqJob.data.source) {
|
|
3645
3840
|
throw new Error("No source set for embedder job.");
|
|
3646
3841
|
}
|
|
3647
|
-
const source = context.sources.get(
|
|
3842
|
+
const source = context.sources.get(bullmqJob.data.source);
|
|
3648
3843
|
if (!source) {
|
|
3649
|
-
throw new Error(`Source ${
|
|
3844
|
+
throw new Error(`Source ${bullmqJob.data.source} not found in the registry.`);
|
|
3650
3845
|
}
|
|
3651
|
-
if (!
|
|
3846
|
+
if (!bullmqJob.data.updater) {
|
|
3652
3847
|
throw new Error("No updater set for embedder job.");
|
|
3653
3848
|
}
|
|
3654
|
-
const updater = source.updaters.find((updater2) => updater2.id ===
|
|
3849
|
+
const updater = source.updaters.find((updater2) => updater2.id === bullmqJob.data.updater);
|
|
3655
3850
|
if (!updater) {
|
|
3656
|
-
throw new Error(`Updater ${
|
|
3851
|
+
throw new Error(`Updater ${bullmqJob.data.updater} not found in the registry.`);
|
|
3657
3852
|
}
|
|
3658
|
-
if (!
|
|
3853
|
+
if (!bullmqJob.data.documents) {
|
|
3659
3854
|
throw new Error("No input documents set for embedder job.");
|
|
3660
3855
|
}
|
|
3661
|
-
if (!Array.isArray(
|
|
3856
|
+
if (!Array.isArray(bullmqJob.data.documents)) {
|
|
3662
3857
|
throw new Error("Input documents must be an array.");
|
|
3663
3858
|
}
|
|
3664
|
-
const result = await embedder.upsert(
|
|
3859
|
+
const result = await embedder.upsert(bullmqJob.data.context, bullmqJob.data.documents, {
|
|
3665
3860
|
label: context.name,
|
|
3666
|
-
trigger:
|
|
3861
|
+
trigger: bullmqJob.data.trigger || "unknown"
|
|
3667
3862
|
});
|
|
3668
|
-
const mongoRecord = await db2.from("jobs").where({ redis:
|
|
3863
|
+
const mongoRecord = await db2.from("jobs").where({ redis: bullmqJob.id }).first();
|
|
3669
3864
|
if (!mongoRecord) {
|
|
3670
3865
|
throw new Error("Job not found in the database.");
|
|
3671
3866
|
}
|
|
3672
3867
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
3673
3868
|
const duration = (finishedAt.getTime() - new Date(mongoRecord.createdAt).getTime()) / 1e3;
|
|
3674
|
-
await db2.from("jobs").where({ redis:
|
|
3869
|
+
await db2.from("jobs").where({ redis: bullmqJob.id }).update({
|
|
3675
3870
|
status: "completed",
|
|
3676
3871
|
finishedAt,
|
|
3677
3872
|
duration,
|
|
@@ -3679,19 +3874,19 @@ var createWorkers = async (queues2, contexts, embedders, workflows, _logsDir) =>
|
|
|
3679
3874
|
});
|
|
3680
3875
|
return result;
|
|
3681
3876
|
}
|
|
3682
|
-
if (
|
|
3683
|
-
const workflow = workflows.find((workflow2) => workflow2.id ===
|
|
3877
|
+
if (bullmqJob.data.type === "workflow") {
|
|
3878
|
+
const workflow = workflows.find((workflow2) => workflow2.id === bullmqJob.data.workflow);
|
|
3684
3879
|
if (!workflow) {
|
|
3685
|
-
throw new Error(`Workflow ${
|
|
3880
|
+
throw new Error(`Workflow ${bullmqJob.data.workflow} not found in the registry.`);
|
|
3686
3881
|
}
|
|
3687
|
-
const
|
|
3688
|
-
|
|
3689
|
-
if (!mongoRecord) {
|
|
3882
|
+
const exuluJob = await db2.from("jobs").where({ redis: bullmqJob.id }).first();
|
|
3883
|
+
if (!exuluJob) {
|
|
3690
3884
|
throw new Error("Job not found in the database.");
|
|
3691
3885
|
}
|
|
3886
|
+
const result = await bullmq.process.workflow(bullmqJob, exuluJob, workflow, logsDir);
|
|
3692
3887
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
3693
|
-
const duration = (finishedAt.getTime() - new Date(
|
|
3694
|
-
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({
|
|
3695
3890
|
status: "completed",
|
|
3696
3891
|
finishedAt,
|
|
3697
3892
|
duration,
|
|
@@ -3700,7 +3895,7 @@ var createWorkers = async (queues2, contexts, embedders, workflows, _logsDir) =>
|
|
|
3700
3895
|
return result;
|
|
3701
3896
|
}
|
|
3702
3897
|
} catch (error) {
|
|
3703
|
-
await db2.from("jobs").where({ redis:
|
|
3898
|
+
await db2.from("jobs").where({ redis: bullmqJob.id }).update({
|
|
3704
3899
|
status: "failed",
|
|
3705
3900
|
finishedAt: /* @__PURE__ */ new Date(),
|
|
3706
3901
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -3729,7 +3924,7 @@ var createWorkers = async (queues2, contexts, embedders, workflows, _logsDir) =>
|
|
|
3729
3924
|
return workers;
|
|
3730
3925
|
};
|
|
3731
3926
|
var createLogsCleanerWorker = (logsDir) => {
|
|
3732
|
-
const logsCleaner = new
|
|
3927
|
+
const logsCleaner = new import_bullmq7.Worker(
|
|
3733
3928
|
global_queues.logs_cleaner,
|
|
3734
3929
|
async (job) => {
|
|
3735
3930
|
console.log(`[EXULU] recurring job ${job.id}.`);
|
|
@@ -3842,12 +4037,18 @@ var ExuluApp = class {
|
|
|
3842
4037
|
};
|
|
3843
4038
|
|
|
3844
4039
|
// src/index.ts
|
|
4040
|
+
var import_chonkie = require("chonkie");
|
|
3845
4041
|
var ExuluJobs = {
|
|
3846
4042
|
redis: redisClient,
|
|
3847
4043
|
jobs: {
|
|
3848
4044
|
validate: validateJob
|
|
3849
4045
|
}
|
|
3850
4046
|
};
|
|
4047
|
+
var ExuluChunkers = {
|
|
4048
|
+
chonkie: {
|
|
4049
|
+
sentence: import_chonkie.SentenceChunker
|
|
4050
|
+
}
|
|
4051
|
+
};
|
|
3851
4052
|
var ExuluDatabase = {
|
|
3852
4053
|
init: async () => {
|
|
3853
4054
|
await execute();
|
|
@@ -3858,14 +4059,17 @@ var ExuluDatabase = {
|
|
|
3858
4059
|
};
|
|
3859
4060
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3860
4061
|
0 && (module.exports = {
|
|
4062
|
+
EXULU_JOB_STATUS_ENUM,
|
|
3861
4063
|
EXULU_STATISTICS_TYPE_ENUM,
|
|
3862
4064
|
ExuluAgent,
|
|
3863
4065
|
ExuluApp,
|
|
3864
4066
|
ExuluAuthentication,
|
|
4067
|
+
ExuluChunkers,
|
|
3865
4068
|
ExuluContext,
|
|
3866
4069
|
ExuluDatabase,
|
|
3867
4070
|
ExuluEmbedder,
|
|
3868
4071
|
ExuluJobs,
|
|
4072
|
+
ExuluLogger,
|
|
3869
4073
|
ExuluQueues,
|
|
3870
4074
|
ExuluSource,
|
|
3871
4075
|
ExuluTool,
|