@exulu/backend 1.15.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -35
- package/dist/index.cjs +359 -259
- package/dist/index.d.cts +34 -20
- package/dist/index.d.ts +34 -20
- package/dist/index.js +355 -256
- package/documentation/logging.md +122 -0
- package/documentation/otel.md +145 -0
- package/package.json +15 -4
- package/lms.md +0 -3
package/dist/index.cjs
CHANGED
|
@@ -41,6 +41,7 @@ __export(index_exports, {
|
|
|
41
41
|
ExuluEval: () => ExuluEval,
|
|
42
42
|
ExuluJobs: () => ExuluJobs,
|
|
43
43
|
ExuluLogger: () => ExuluLogger,
|
|
44
|
+
ExuluOtel: () => ExuluOtel,
|
|
44
45
|
ExuluQueues: () => queues,
|
|
45
46
|
ExuluSource: () => ExuluSource,
|
|
46
47
|
ExuluTool: () => ExuluTool,
|
|
@@ -217,87 +218,48 @@ var import_knex4 = __toESM(require("pgvector/knex"), 1);
|
|
|
217
218
|
var import_bullmq = require("bullmq");
|
|
218
219
|
var import_uuid = require("uuid");
|
|
219
220
|
var bullmqDecorator = async ({
|
|
221
|
+
queue,
|
|
220
222
|
label,
|
|
221
|
-
type,
|
|
222
|
-
workflow,
|
|
223
223
|
embedder,
|
|
224
224
|
inputs,
|
|
225
|
-
queue,
|
|
226
225
|
user,
|
|
227
|
-
|
|
228
|
-
session,
|
|
229
|
-
configuration,
|
|
230
|
-
updater,
|
|
231
|
-
context,
|
|
232
|
-
steps,
|
|
233
|
-
source,
|
|
234
|
-
documents,
|
|
226
|
+
role,
|
|
235
227
|
trigger,
|
|
236
|
-
|
|
228
|
+
workflow,
|
|
229
|
+
item,
|
|
230
|
+
context
|
|
237
231
|
}) => {
|
|
232
|
+
if (embedder && workflow) {
|
|
233
|
+
throw new Error("Cannot have both embedder and workflow in the same job.");
|
|
234
|
+
}
|
|
235
|
+
if (workflow && item) {
|
|
236
|
+
throw new Error("Cannot have both workflow and item in the same job.");
|
|
237
|
+
}
|
|
238
|
+
let type = "embedder";
|
|
239
|
+
if (workflow) {
|
|
240
|
+
type = "workflow";
|
|
241
|
+
}
|
|
238
242
|
const redisId = (0, import_uuid.v4)();
|
|
239
243
|
const job = await queue.add(
|
|
240
244
|
`${embedder || workflow}`,
|
|
241
245
|
{
|
|
242
|
-
|
|
246
|
+
label,
|
|
243
247
|
...embedder && { embedder },
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
...
|
|
247
|
-
...
|
|
248
|
-
...source && { source },
|
|
249
|
-
...documents && { documents },
|
|
250
|
-
...steps && { steps },
|
|
248
|
+
type: `${type}`,
|
|
249
|
+
inputs,
|
|
250
|
+
...user && { user },
|
|
251
|
+
...role && { role },
|
|
251
252
|
...trigger && { trigger },
|
|
253
|
+
...workflow && { workflow },
|
|
252
254
|
...item && { item },
|
|
253
|
-
|
|
254
|
-
user,
|
|
255
|
-
inputs,
|
|
256
|
-
label,
|
|
257
|
-
session
|
|
255
|
+
...context && { context }
|
|
258
256
|
},
|
|
259
257
|
{
|
|
260
258
|
jobId: redisId
|
|
261
259
|
}
|
|
262
260
|
);
|
|
263
|
-
const { db: db3 } = await postgresClient();
|
|
264
|
-
const now = /* @__PURE__ */ new Date();
|
|
265
|
-
console.log("[EXULU] scheduling new job", inputs);
|
|
266
|
-
const insertData = {
|
|
267
|
-
name: `${label}`,
|
|
268
|
-
redis: job.id,
|
|
269
|
-
status: "waiting",
|
|
270
|
-
type,
|
|
271
|
-
inputs,
|
|
272
|
-
agent,
|
|
273
|
-
item,
|
|
274
|
-
createdAt: now,
|
|
275
|
-
updatedAt: now,
|
|
276
|
-
user,
|
|
277
|
-
session,
|
|
278
|
-
...embedder && { embedder },
|
|
279
|
-
...workflow && { workflow },
|
|
280
|
-
...configuration && { configuration },
|
|
281
|
-
...steps && { steps },
|
|
282
|
-
...updater && { updater },
|
|
283
|
-
...context && { context },
|
|
284
|
-
...source && { source },
|
|
285
|
-
...documents && { documents: documents.map((doc2) => doc2.id) },
|
|
286
|
-
...trigger && { trigger }
|
|
287
|
-
};
|
|
288
|
-
await db3("jobs").insert(insertData).onConflict("redis").merge({
|
|
289
|
-
...insertData,
|
|
290
|
-
updatedAt: now
|
|
291
|
-
// Only updatedAt changes on updates
|
|
292
|
-
});
|
|
293
|
-
const doc = await db3.from("jobs").where({ redis: job.id }).first();
|
|
294
|
-
if (!doc?.id) {
|
|
295
|
-
throw new Error("Failed to get job ID after insert/update");
|
|
296
|
-
}
|
|
297
|
-
console.log("[EXULU] created job", doc?.id);
|
|
298
261
|
return {
|
|
299
262
|
...job,
|
|
300
|
-
id: doc?.id,
|
|
301
263
|
redis: job.id
|
|
302
264
|
};
|
|
303
265
|
};
|
|
@@ -469,6 +431,7 @@ var ExuluEvalUtils = {
|
|
|
469
431
|
// src/registry/classes.ts
|
|
470
432
|
var import_crypto_js = __toESM(require("crypto-js"), 1);
|
|
471
433
|
var import_express = require("express");
|
|
434
|
+
var import_api = require("@opentelemetry/api");
|
|
472
435
|
function sanitizeToolName(name) {
|
|
473
436
|
if (typeof name !== "string") return "";
|
|
474
437
|
let sanitized = name.replace(/[^a-zA-Z0-9_-]+/g, "_");
|
|
@@ -478,7 +441,7 @@ function sanitizeToolName(name) {
|
|
|
478
441
|
}
|
|
479
442
|
return sanitized;
|
|
480
443
|
}
|
|
481
|
-
var convertToolsArrayToObject = (tools, configs, providerApiKey) => {
|
|
444
|
+
var convertToolsArrayToObject = (tools, configs, providerApiKey, user, role) => {
|
|
482
445
|
if (!tools) return {};
|
|
483
446
|
const sanitizedTools = tools ? tools.map((tool2) => ({
|
|
484
447
|
...tool2,
|
|
@@ -513,6 +476,8 @@ var convertToolsArrayToObject = (tools, configs, providerApiKey) => {
|
|
|
513
476
|
// is available, after we added the .value property
|
|
514
477
|
// by hydrating it from the variables table.
|
|
515
478
|
providerApiKey,
|
|
479
|
+
user,
|
|
480
|
+
role,
|
|
516
481
|
config: config ? config.config.reduce((acc, curr) => {
|
|
517
482
|
acc[curr.name] = curr.value;
|
|
518
483
|
return acc;
|
|
@@ -618,10 +583,12 @@ var ExuluAgent = class {
|
|
|
618
583
|
}),
|
|
619
584
|
description: `A function that calls an AI agent named: ${this.name}. The agent does the following: ${this.description}.`,
|
|
620
585
|
config: [],
|
|
621
|
-
execute: async ({ prompt, config, providerApiKey }) => {
|
|
586
|
+
execute: async ({ prompt, config, providerApiKey, user, role }) => {
|
|
622
587
|
return await this.generateSync({
|
|
623
588
|
prompt,
|
|
624
589
|
providerApiKey,
|
|
590
|
+
user,
|
|
591
|
+
role,
|
|
625
592
|
statistics: {
|
|
626
593
|
label: "",
|
|
627
594
|
trigger: "tool"
|
|
@@ -630,7 +597,7 @@ var ExuluAgent = class {
|
|
|
630
597
|
}
|
|
631
598
|
});
|
|
632
599
|
};
|
|
633
|
-
generateSync = async ({ prompt, user, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
600
|
+
generateSync = async ({ prompt, user, role, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
634
601
|
if (!this.model) {
|
|
635
602
|
throw new Error("Model is required for streaming.");
|
|
636
603
|
}
|
|
@@ -640,6 +607,9 @@ var ExuluAgent = class {
|
|
|
640
607
|
if (prompt && message) {
|
|
641
608
|
throw new Error("Message and prompt cannot be provided at the same time.");
|
|
642
609
|
}
|
|
610
|
+
if (!prompt && !message) {
|
|
611
|
+
throw new Error("Prompt or message is required for generating.");
|
|
612
|
+
}
|
|
643
613
|
const model = this.model.create({
|
|
644
614
|
apiKey: providerApiKey
|
|
645
615
|
});
|
|
@@ -659,28 +629,54 @@ var ExuluAgent = class {
|
|
|
659
629
|
}
|
|
660
630
|
console.log("[EXULU] Model provider key", providerApiKey);
|
|
661
631
|
console.log("[EXULU] Tool configs", toolConfigs);
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
632
|
+
if (prompt) {
|
|
633
|
+
const { text } = await (0, import_ai.generateText)({
|
|
634
|
+
model,
|
|
635
|
+
// Should be a LanguageModelV1
|
|
636
|
+
system: "You are a helpful assistant. When you use a tool to answer a question do not explicitly comment on the result of the tool call unless the user has explicitly you to do something with the result.",
|
|
637
|
+
prompt,
|
|
638
|
+
maxRetries: 2,
|
|
639
|
+
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey, user, role),
|
|
640
|
+
stopWhen: [(0, import_ai.stepCountIs)(5)]
|
|
641
|
+
});
|
|
642
|
+
if (statistics) {
|
|
643
|
+
await updateStatistic({
|
|
644
|
+
name: "count",
|
|
645
|
+
label: statistics.label,
|
|
646
|
+
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
647
|
+
trigger: statistics.trigger,
|
|
648
|
+
count: 1,
|
|
649
|
+
user,
|
|
650
|
+
role
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
return text;
|
|
654
|
+
}
|
|
655
|
+
if (messages) {
|
|
656
|
+
const { text } = await (0, import_ai.generateText)({
|
|
657
|
+
model,
|
|
658
|
+
// Should be a LanguageModelV1
|
|
659
|
+
system: "You are a helpful assistant. When you use a tool to answer a question do not explicitly comment on the result of the tool call unless the user has explicitly you to do something with the result.",
|
|
660
|
+
messages: (0, import_ai.convertToModelMessages)(messages),
|
|
661
|
+
maxRetries: 2,
|
|
662
|
+
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey, user, role),
|
|
663
|
+
stopWhen: [(0, import_ai.stepCountIs)(5)]
|
|
679
664
|
});
|
|
665
|
+
if (statistics) {
|
|
666
|
+
await updateStatistic({
|
|
667
|
+
name: "count",
|
|
668
|
+
label: statistics.label,
|
|
669
|
+
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
670
|
+
trigger: statistics.trigger,
|
|
671
|
+
count: 1,
|
|
672
|
+
user,
|
|
673
|
+
role
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
return text;
|
|
680
677
|
}
|
|
681
|
-
return text;
|
|
682
678
|
};
|
|
683
|
-
generateStream = async ({ express: express3, user, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
679
|
+
generateStream = async ({ express: express3, user, role, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
684
680
|
if (!this.model) {
|
|
685
681
|
throw new Error("Model is required for streaming.");
|
|
686
682
|
}
|
|
@@ -710,10 +706,10 @@ var ExuluAgent = class {
|
|
|
710
706
|
const result = (0, import_ai.streamText)({
|
|
711
707
|
model,
|
|
712
708
|
// Should be a LanguageModelV1
|
|
713
|
-
messages:
|
|
709
|
+
messages: (0, import_ai.convertToModelMessages)(messages),
|
|
714
710
|
system: "You are a helpful assistant. When you use a tool to answer a question do not explicitly comment on the result of the tool call unless the user has explicitly you to do something with the result.",
|
|
715
711
|
maxRetries: 2,
|
|
716
|
-
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey),
|
|
712
|
+
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey, user, role),
|
|
717
713
|
onError: (error) => console.error("[EXULU] chat stream error.", error),
|
|
718
714
|
stopWhen: [(0, import_ai.stepCountIs)(5)]
|
|
719
715
|
});
|
|
@@ -741,7 +737,9 @@ var ExuluAgent = class {
|
|
|
741
737
|
label: statistics.label,
|
|
742
738
|
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
743
739
|
trigger: statistics.trigger,
|
|
744
|
-
count: 1
|
|
740
|
+
count: 1,
|
|
741
|
+
user,
|
|
742
|
+
role
|
|
745
743
|
});
|
|
746
744
|
}
|
|
747
745
|
}
|
|
@@ -785,14 +783,16 @@ var ExuluEmbedder = class {
|
|
|
785
783
|
this.queue = queue;
|
|
786
784
|
this.generateEmbeddings = generateEmbeddings;
|
|
787
785
|
}
|
|
788
|
-
async generateFromQuery(query, statistics) {
|
|
786
|
+
async generateFromQuery(query, statistics, user, role) {
|
|
789
787
|
if (statistics) {
|
|
790
788
|
await updateStatistic({
|
|
791
789
|
name: "count",
|
|
792
790
|
label: statistics.label,
|
|
793
791
|
type: STATISTICS_TYPE_ENUM.EMBEDDER_GENERATE,
|
|
794
792
|
trigger: statistics.trigger,
|
|
795
|
-
count: 1
|
|
793
|
+
count: 1,
|
|
794
|
+
user,
|
|
795
|
+
role
|
|
796
796
|
});
|
|
797
797
|
}
|
|
798
798
|
return await this.generateEmbeddings({
|
|
@@ -805,14 +805,16 @@ var ExuluEmbedder = class {
|
|
|
805
805
|
}]
|
|
806
806
|
});
|
|
807
807
|
}
|
|
808
|
-
async generateFromDocument(input, statistics) {
|
|
808
|
+
async generateFromDocument(input, statistics, user, role) {
|
|
809
809
|
if (statistics) {
|
|
810
810
|
await updateStatistic({
|
|
811
811
|
name: "count",
|
|
812
812
|
label: statistics.label,
|
|
813
813
|
type: STATISTICS_TYPE_ENUM.EMBEDDER_GENERATE,
|
|
814
814
|
trigger: statistics.trigger,
|
|
815
|
-
count: 1
|
|
815
|
+
count: 1,
|
|
816
|
+
user,
|
|
817
|
+
role
|
|
816
818
|
});
|
|
817
819
|
}
|
|
818
820
|
if (!this.chunker) {
|
|
@@ -1066,8 +1068,36 @@ var ExuluContext = class {
|
|
|
1066
1068
|
const tableExists = await db3.schema.hasTable(this.getTableName());
|
|
1067
1069
|
return tableExists;
|
|
1068
1070
|
};
|
|
1069
|
-
async
|
|
1070
|
-
|
|
1071
|
+
createAndUpsertEmbeddings = async (item, user, statistics, role) => {
|
|
1072
|
+
const { db: db3 } = await postgresClient();
|
|
1073
|
+
const { id: source, chunks } = await this.embedder.generateFromDocument({
|
|
1074
|
+
...item,
|
|
1075
|
+
id: item.id
|
|
1076
|
+
}, {
|
|
1077
|
+
label: statistics.label || this.name,
|
|
1078
|
+
trigger: statistics.trigger || "agent"
|
|
1079
|
+
}, user, role);
|
|
1080
|
+
const exists = await db3.schema.hasTable(this.getChunksTableName());
|
|
1081
|
+
if (!exists) {
|
|
1082
|
+
await this.createChunksTable();
|
|
1083
|
+
}
|
|
1084
|
+
await db3.from(this.getChunksTableName()).where({ source }).delete();
|
|
1085
|
+
await db3.from(this.getChunksTableName()).insert(chunks.map((chunk) => ({
|
|
1086
|
+
source,
|
|
1087
|
+
content: chunk.content,
|
|
1088
|
+
chunk_index: chunk.index,
|
|
1089
|
+
embedding: import_knex4.default.toSql(chunk.vector)
|
|
1090
|
+
})));
|
|
1091
|
+
await db3.from(this.getTableName()).where({ id: item.id }).update({
|
|
1092
|
+
embeddings_updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1093
|
+
}).returning("id");
|
|
1094
|
+
return {
|
|
1095
|
+
id: item.id,
|
|
1096
|
+
chunks: chunks?.length || 0
|
|
1097
|
+
};
|
|
1098
|
+
};
|
|
1099
|
+
async updateItem(user, item, role, trigger) {
|
|
1100
|
+
if (!item.id) {
|
|
1071
1101
|
throw new Error("Id is required for updating an item.");
|
|
1072
1102
|
}
|
|
1073
1103
|
const { db: db3 } = await postgresClient();
|
|
@@ -1084,51 +1114,37 @@ var ExuluContext = class {
|
|
|
1084
1114
|
delete item.created_at;
|
|
1085
1115
|
delete item.upsert;
|
|
1086
1116
|
item.updated_at = db3.fn.now();
|
|
1087
|
-
const result = await db3.from(this.getTableName()).where({ id }).update(item).returning("id");
|
|
1117
|
+
const result = await db3.from(this.getTableName()).where({ id: item.id }).update(item).returning("id");
|
|
1088
1118
|
if (this.configuration.calculateVectors === "onUpdate" || this.configuration.calculateVectors === "always") {
|
|
1089
1119
|
if (this.embedder.queue?.name) {
|
|
1090
1120
|
console.log("[EXULU] embedder is in queue mode, scheduling job.");
|
|
1091
1121
|
const job = await bullmqDecorator({
|
|
1092
|
-
label:
|
|
1122
|
+
label: `${this.embedder.name}`,
|
|
1093
1123
|
embedder: this.embedder.id,
|
|
1094
|
-
|
|
1124
|
+
context: this.id,
|
|
1095
1125
|
inputs: item,
|
|
1126
|
+
item: item.id,
|
|
1096
1127
|
queue: this.embedder.queue,
|
|
1097
|
-
user
|
|
1128
|
+
user,
|
|
1129
|
+
role,
|
|
1130
|
+
trigger: trigger || "agent"
|
|
1098
1131
|
});
|
|
1099
1132
|
return {
|
|
1100
1133
|
id: result[0].id,
|
|
1101
1134
|
job: job.id
|
|
1102
1135
|
};
|
|
1103
1136
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
},
|
|
1108
|
-
label: this.name,
|
|
1109
|
-
trigger: "agent"
|
|
1110
|
-
});
|
|
1111
|
-
const exists = await db3.schema.hasTable(this.getChunksTableName());
|
|
1112
|
-
if (!exists) {
|
|
1113
|
-
await this.createChunksTable();
|
|
1114
|
-
}
|
|
1115
|
-
await db3.from(this.getChunksTableName()).where({ source }).delete();
|
|
1116
|
-
await db3.from(this.getChunksTableName()).insert(chunks.map((chunk) => ({
|
|
1117
|
-
source,
|
|
1118
|
-
content: chunk.content,
|
|
1119
|
-
chunk_index: chunk.index,
|
|
1120
|
-
embedding: import_knex4.default.toSql(chunk.vector)
|
|
1121
|
-
})));
|
|
1122
|
-
await db3.from(this.getTableName()).where({ id }).update({
|
|
1123
|
-
embeddings_updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1124
|
-
}).returning("id");
|
|
1137
|
+
await this.createAndUpsertEmbeddings(item, user, {
|
|
1138
|
+
label: this.embedder.name,
|
|
1139
|
+
trigger: trigger || "agent"
|
|
1140
|
+
}, role);
|
|
1125
1141
|
}
|
|
1126
1142
|
return {
|
|
1127
1143
|
id: result[0].id,
|
|
1128
1144
|
job: void 0
|
|
1129
1145
|
};
|
|
1130
1146
|
}
|
|
1131
|
-
async insertItem(user, item, upsert = false) {
|
|
1147
|
+
async insertItem(user, item, upsert = false, role, trigger) {
|
|
1132
1148
|
if (!item.name) {
|
|
1133
1149
|
throw new Error("Name field is required.");
|
|
1134
1150
|
}
|
|
@@ -1139,14 +1155,20 @@ var ExuluContext = class {
|
|
|
1139
1155
|
throw new Error("Item with external id " + item.external_id + " already exists.");
|
|
1140
1156
|
}
|
|
1141
1157
|
if (existingItem && upsert) {
|
|
1142
|
-
await this.updateItem(user,
|
|
1158
|
+
await this.updateItem(user, {
|
|
1159
|
+
...item,
|
|
1160
|
+
id: existingItem.id
|
|
1161
|
+
}, role, trigger);
|
|
1143
1162
|
return existingItem.id;
|
|
1144
1163
|
}
|
|
1145
1164
|
}
|
|
1146
1165
|
if (upsert && item.id) {
|
|
1147
1166
|
const existingItem = await db3.from(this.getTableName()).where({ id: item.id }).first();
|
|
1148
1167
|
if (existingItem && upsert) {
|
|
1149
|
-
await this.updateItem(user,
|
|
1168
|
+
await this.updateItem(user, {
|
|
1169
|
+
...item,
|
|
1170
|
+
id: existingItem.id
|
|
1171
|
+
}, role, trigger);
|
|
1150
1172
|
return existingItem.id;
|
|
1151
1173
|
}
|
|
1152
1174
|
}
|
|
@@ -1171,12 +1193,15 @@ var ExuluContext = class {
|
|
|
1171
1193
|
if (this.embedder.queue?.name) {
|
|
1172
1194
|
console.log("[EXULU] embedder is in queue mode, scheduling job.");
|
|
1173
1195
|
const job = await bullmqDecorator({
|
|
1174
|
-
label:
|
|
1196
|
+
label: `${this.embedder.name}`,
|
|
1175
1197
|
embedder: this.embedder.id,
|
|
1176
|
-
|
|
1198
|
+
context: this.id,
|
|
1177
1199
|
inputs: item,
|
|
1200
|
+
item: item.id,
|
|
1178
1201
|
queue: this.embedder.queue,
|
|
1179
|
-
user
|
|
1202
|
+
user,
|
|
1203
|
+
role,
|
|
1204
|
+
trigger: trigger || "agent"
|
|
1180
1205
|
});
|
|
1181
1206
|
return {
|
|
1182
1207
|
id: result[0].id,
|
|
@@ -1184,27 +1209,13 @@ var ExuluContext = class {
|
|
|
1184
1209
|
};
|
|
1185
1210
|
}
|
|
1186
1211
|
console.log("[EXULU] embedder is not in queue mode, calculating vectors directly.");
|
|
1187
|
-
|
|
1212
|
+
await this.createAndUpsertEmbeddings({
|
|
1188
1213
|
...item,
|
|
1189
1214
|
id: result[0].id
|
|
1190
|
-
}, {
|
|
1191
|
-
label: this.name,
|
|
1192
|
-
trigger: "agent"
|
|
1193
|
-
});
|
|
1194
|
-
const exists = await db3.schema.hasTable(this.getChunksTableName());
|
|
1195
|
-
if (!exists) {
|
|
1196
|
-
await this.createChunksTable();
|
|
1197
|
-
}
|
|
1198
|
-
console.log("[EXULU] Inserting chunks.");
|
|
1199
|
-
await db3.from(this.getChunksTableName()).insert(chunks.map((chunk) => ({
|
|
1200
|
-
source,
|
|
1201
|
-
content: chunk.content,
|
|
1202
|
-
chunk_index: chunk.index,
|
|
1203
|
-
embedding: import_knex4.default.toSql(chunk.vector)
|
|
1204
|
-
})));
|
|
1205
|
-
await db3.from(this.getTableName()).where({ id: result[0].id }).update({
|
|
1206
|
-
embeddings_updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1207
|
-
}).returning("id");
|
|
1215
|
+
}, user, {
|
|
1216
|
+
label: this.embedder.name,
|
|
1217
|
+
trigger: trigger || "agent"
|
|
1218
|
+
}, role);
|
|
1208
1219
|
}
|
|
1209
1220
|
return {
|
|
1210
1221
|
id: result[0].id,
|
|
@@ -1218,6 +1229,8 @@ var ExuluContext = class {
|
|
|
1218
1229
|
order,
|
|
1219
1230
|
page,
|
|
1220
1231
|
name,
|
|
1232
|
+
user,
|
|
1233
|
+
role,
|
|
1221
1234
|
archived,
|
|
1222
1235
|
query,
|
|
1223
1236
|
method
|
|
@@ -1286,7 +1299,9 @@ var ExuluContext = class {
|
|
|
1286
1299
|
name: "count",
|
|
1287
1300
|
label: statistics.label,
|
|
1288
1301
|
type: STATISTICS_TYPE_ENUM.CONTEXT_RETRIEVE,
|
|
1289
|
-
trigger: statistics.trigger
|
|
1302
|
+
trigger: statistics.trigger,
|
|
1303
|
+
user,
|
|
1304
|
+
role
|
|
1290
1305
|
});
|
|
1291
1306
|
}
|
|
1292
1307
|
if (this.queryRewriter) {
|
|
@@ -1302,7 +1317,10 @@ var ExuluContext = class {
|
|
|
1302
1317
|
itemsQuery.select(chunksTable + ".chunk_index");
|
|
1303
1318
|
itemsQuery.select(chunksTable + ".created_at as chunk_created_at");
|
|
1304
1319
|
itemsQuery.select(chunksTable + ".updated_at as chunk_updated_at");
|
|
1305
|
-
const { chunks } = await this.embedder.generateFromQuery(query
|
|
1320
|
+
const { chunks } = await this.embedder.generateFromQuery(query, {
|
|
1321
|
+
label: this.name,
|
|
1322
|
+
trigger: "agent"
|
|
1323
|
+
}, user, role);
|
|
1306
1324
|
if (!chunks?.[0]?.vector) {
|
|
1307
1325
|
throw new Error("No vector generated for query.");
|
|
1308
1326
|
}
|
|
@@ -1450,11 +1468,13 @@ var ExuluContext = class {
|
|
|
1450
1468
|
}),
|
|
1451
1469
|
config: [],
|
|
1452
1470
|
description: `Gets information from the context called: ${this.name}. The context description is: ${this.description}.`,
|
|
1453
|
-
execute: async ({ query }) => {
|
|
1471
|
+
execute: async ({ query, user, role }) => {
|
|
1454
1472
|
return await this.getItems({
|
|
1455
1473
|
page: 1,
|
|
1456
1474
|
limit: 10,
|
|
1457
1475
|
query,
|
|
1476
|
+
user,
|
|
1477
|
+
role,
|
|
1458
1478
|
statistics: {
|
|
1459
1479
|
label: this.name,
|
|
1460
1480
|
trigger: "agent"
|
|
@@ -1896,6 +1916,7 @@ var import_zodex = require("zodex");
|
|
|
1896
1916
|
|
|
1897
1917
|
// src/bullmq/queues.ts
|
|
1898
1918
|
var import_bullmq4 = require("bullmq");
|
|
1919
|
+
var import_bullmq_otel = require("bullmq-otel");
|
|
1899
1920
|
var ExuluQueues = class {
|
|
1900
1921
|
queues;
|
|
1901
1922
|
constructor() {
|
|
@@ -1913,7 +1934,13 @@ var ExuluQueues = class {
|
|
|
1913
1934
|
console.error(`[EXULU] no redis server configured, but you are trying to use a queue ( ${name}), likely in an agent or embedder (look for ExuluQueues.use() ).`);
|
|
1914
1935
|
throw new Error(`[EXULU] no redis server configured.`);
|
|
1915
1936
|
}
|
|
1916
|
-
const newQueue = new import_bullmq4.Queue(
|
|
1937
|
+
const newQueue = new import_bullmq4.Queue(
|
|
1938
|
+
`${name}`,
|
|
1939
|
+
{
|
|
1940
|
+
connection: redisServer,
|
|
1941
|
+
telemetry: new import_bullmq_otel.BullMQOtel("simple-guide")
|
|
1942
|
+
}
|
|
1943
|
+
);
|
|
1917
1944
|
this.queues.push(newQueue);
|
|
1918
1945
|
return newQueue;
|
|
1919
1946
|
}
|
|
@@ -3700,6 +3727,7 @@ Intelligence Management Platform
|
|
|
3700
3727
|
var import_openai = __toESM(require("openai"), 1);
|
|
3701
3728
|
var import_fs = __toESM(require("fs"), 1);
|
|
3702
3729
|
var import_node_crypto = require("crypto");
|
|
3730
|
+
var import_api2 = require("@opentelemetry/api");
|
|
3703
3731
|
var REQUEST_SIZE_LIMIT = "50mb";
|
|
3704
3732
|
var global_queues = {
|
|
3705
3733
|
logs_cleaner: "logs-cleaner"
|
|
@@ -3738,7 +3766,7 @@ var createRecurringJobs = async () => {
|
|
|
3738
3766
|
console.table(recurringJobSchedulersLogs);
|
|
3739
3767
|
return queue;
|
|
3740
3768
|
};
|
|
3741
|
-
var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
3769
|
+
var createExpressRoutes = async (app, logger, agents, tools, contexts, config, tracer) => {
|
|
3742
3770
|
const routeLogs = [];
|
|
3743
3771
|
var corsOptions = {
|
|
3744
3772
|
origin: "*",
|
|
@@ -3832,6 +3860,16 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
3832
3860
|
import_express4.default.json({ limit: REQUEST_SIZE_LIMIT }),
|
|
3833
3861
|
(0, import_express5.expressMiddleware)(server, {
|
|
3834
3862
|
context: async ({ req }) => {
|
|
3863
|
+
logger.info("================");
|
|
3864
|
+
logger.info({
|
|
3865
|
+
message: "Incoming Request",
|
|
3866
|
+
method: req.method,
|
|
3867
|
+
path: req.path,
|
|
3868
|
+
requestId: "req-" + Date.now(),
|
|
3869
|
+
ipAddress: req.ip,
|
|
3870
|
+
userAgent: req.get("User-Agent")
|
|
3871
|
+
});
|
|
3872
|
+
logger.info("================");
|
|
3835
3873
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
3836
3874
|
if (!authenticationResult.user?.id) {
|
|
3837
3875
|
throw new Error(authenticationResult.message);
|
|
@@ -4218,7 +4256,15 @@ Mood: friendly and intelligent.
|
|
|
4218
4256
|
if (!exists) {
|
|
4219
4257
|
await context.createItemsTable();
|
|
4220
4258
|
}
|
|
4221
|
-
const result = await context.updateItem(
|
|
4259
|
+
const result = await context.updateItem(
|
|
4260
|
+
authenticationResult.user.id,
|
|
4261
|
+
{
|
|
4262
|
+
...req.body,
|
|
4263
|
+
id: req.params.id
|
|
4264
|
+
},
|
|
4265
|
+
authenticationResult.user.role?.id,
|
|
4266
|
+
authenticationResult.user.type === "api" ? "api" : "user"
|
|
4267
|
+
);
|
|
4222
4268
|
res.status(200).json({
|
|
4223
4269
|
message: "Item updated successfully.",
|
|
4224
4270
|
id: result
|
|
@@ -4265,7 +4311,13 @@ Mood: friendly and intelligent.
|
|
|
4265
4311
|
await context.createItemsTable();
|
|
4266
4312
|
}
|
|
4267
4313
|
console.log("[EXULU] inserting item", req.body);
|
|
4268
|
-
const result = await context.insertItem(
|
|
4314
|
+
const result = await context.insertItem(
|
|
4315
|
+
authenticationResult.user.id,
|
|
4316
|
+
req.body,
|
|
4317
|
+
!!req.body.upsert,
|
|
4318
|
+
authenticationResult.user.role?.id,
|
|
4319
|
+
authenticationResult.user.type === "api" ? "api" : "user"
|
|
4320
|
+
);
|
|
4269
4321
|
console.log("[EXULU] result", result);
|
|
4270
4322
|
res.status(200).json({
|
|
4271
4323
|
message: "Item created successfully.",
|
|
@@ -4326,6 +4378,8 @@ Mood: friendly and intelligent.
|
|
|
4326
4378
|
const result = await context.getItems({
|
|
4327
4379
|
sort,
|
|
4328
4380
|
order,
|
|
4381
|
+
user: authenticationResult.user?.id,
|
|
4382
|
+
role: authenticationResult.user?.role?.id,
|
|
4329
4383
|
page,
|
|
4330
4384
|
limit,
|
|
4331
4385
|
archived: req.query.archived === "true",
|
|
@@ -4487,6 +4541,8 @@ Mood: friendly and intelligent.
|
|
|
4487
4541
|
const items = await context.getItems({
|
|
4488
4542
|
page: 1,
|
|
4489
4543
|
// todo add pagination
|
|
4544
|
+
user: authenticationResult.user?.id,
|
|
4545
|
+
role: authenticationResult.user?.role?.id,
|
|
4490
4546
|
limit: 500
|
|
4491
4547
|
});
|
|
4492
4548
|
const csv = Papa.unparse(items);
|
|
@@ -4610,7 +4666,7 @@ Mood: friendly and intelligent.
|
|
|
4610
4666
|
return;
|
|
4611
4667
|
}
|
|
4612
4668
|
console.log("[EXULU] agent tools", agentInstance.tools);
|
|
4613
|
-
const enabledTools = agentInstance.tools.map(({ config, toolId }) => tools.find(({ id }) => id === toolId)).filter(Boolean);
|
|
4669
|
+
const enabledTools = agentInstance.tools.map(({ config: config2, toolId }) => tools.find(({ id }) => id === toolId)).filter(Boolean);
|
|
4614
4670
|
console.log("[EXULU] enabled tools", enabledTools);
|
|
4615
4671
|
const variableName = agentInstance.providerApiKey;
|
|
4616
4672
|
const variable = await db3.from("variables").where({ name: variableName }).first();
|
|
@@ -4637,7 +4693,8 @@ Mood: friendly and intelligent.
|
|
|
4637
4693
|
res,
|
|
4638
4694
|
req
|
|
4639
4695
|
},
|
|
4640
|
-
user:
|
|
4696
|
+
user: user?.id,
|
|
4697
|
+
role: user?.role?.id,
|
|
4641
4698
|
session: headers.session,
|
|
4642
4699
|
message: req.body.message,
|
|
4643
4700
|
tools: enabledTools,
|
|
@@ -4651,8 +4708,9 @@ Mood: friendly and intelligent.
|
|
|
4651
4708
|
return;
|
|
4652
4709
|
} else {
|
|
4653
4710
|
const response = await agent.generateSync({
|
|
4654
|
-
user:
|
|
4711
|
+
user: user?.id,
|
|
4655
4712
|
session: headers.session,
|
|
4713
|
+
role: user?.role?.id,
|
|
4656
4714
|
message: req.body.message,
|
|
4657
4715
|
tools: enabledTools.map((tool2) => tool2.tool),
|
|
4658
4716
|
providerApiKey,
|
|
@@ -4751,7 +4809,9 @@ Mood: friendly and intelligent.
|
|
|
4751
4809
|
label: "Claude Code",
|
|
4752
4810
|
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
4753
4811
|
trigger: "claude-code",
|
|
4754
|
-
count: 1
|
|
4812
|
+
count: 1,
|
|
4813
|
+
user: authenticationResult.user?.id,
|
|
4814
|
+
role: authenticationResult.user.role?.id
|
|
4755
4815
|
});
|
|
4756
4816
|
response.headers.forEach((value, key) => {
|
|
4757
4817
|
res.setHeader(key, value);
|
|
@@ -4809,46 +4869,25 @@ var createCustomAnthropicStreamingMessage = (message) => {
|
|
|
4809
4869
|
|
|
4810
4870
|
// src/registry/workers.ts
|
|
4811
4871
|
var import_ioredis = __toESM(require("ioredis"), 1);
|
|
4812
|
-
var
|
|
4872
|
+
var import_bullmq5 = require("bullmq");
|
|
4813
4873
|
|
|
4814
4874
|
// src/registry/utils.ts
|
|
4815
|
-
var import_bullmq5 = require("bullmq");
|
|
4816
4875
|
var bullmq = {
|
|
4817
|
-
validate: (
|
|
4818
|
-
if (!
|
|
4819
|
-
throw new Error(`Missing job data for job ${
|
|
4820
|
-
}
|
|
4821
|
-
if (!bullmqJob.data.type) {
|
|
4822
|
-
throw new Error(`Missing property "type" in data for job ${bullmqJob.id}.`);
|
|
4876
|
+
validate: (id, data) => {
|
|
4877
|
+
if (!data) {
|
|
4878
|
+
throw new Error(`Missing job data for job ${id}.`);
|
|
4823
4879
|
}
|
|
4824
|
-
if (!
|
|
4825
|
-
throw new Error(`Missing property "
|
|
4880
|
+
if (!data.type) {
|
|
4881
|
+
throw new Error(`Missing property "type" in data for job ${id}.`);
|
|
4826
4882
|
}
|
|
4827
|
-
if (
|
|
4828
|
-
throw new Error(`
|
|
4883
|
+
if (!data.inputs) {
|
|
4884
|
+
throw new Error(`Missing property "inputs" in data for job ${id}.`);
|
|
4829
4885
|
}
|
|
4830
|
-
if (
|
|
4831
|
-
throw new Error(`Property "
|
|
4886
|
+
if (data.type !== "embedder" && data.type !== "workflow") {
|
|
4887
|
+
throw new Error(`Property "type" in data for job ${id} must be of value "embedder" or "workflow".`);
|
|
4832
4888
|
}
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
workflow: async (bullmqJob, exuluJob, workflow, logsDir) => {
|
|
4836
|
-
if (!workflow) {
|
|
4837
|
-
throw new Error(`Workflow function with id: ${bullmqJob.data.backend} not found in registry.`);
|
|
4838
|
-
}
|
|
4839
|
-
console.log("[EXULU] starting workflow with job inputs.", bullmqJob.data.inputs);
|
|
4840
|
-
const logger = new ExuluLogger(exuluJob, logsDir);
|
|
4841
|
-
const output = await workflow.start({
|
|
4842
|
-
job: exuluJob,
|
|
4843
|
-
inputs: bullmqJob.data.inputs,
|
|
4844
|
-
user: bullmqJob.data.user,
|
|
4845
|
-
logger,
|
|
4846
|
-
session: bullmqJob.data.session,
|
|
4847
|
-
agent: bullmqJob.data.agent,
|
|
4848
|
-
label: bullmqJob.data.label
|
|
4849
|
-
});
|
|
4850
|
-
await logger.write(`Workflow completed. ${JSON.stringify(output)}`, "INFO");
|
|
4851
|
-
return output;
|
|
4889
|
+
if (!data.workflow && !data.embedder) {
|
|
4890
|
+
throw new Error(`Either a workflow or embedder must be set for job ${id}.`);
|
|
4852
4891
|
}
|
|
4853
4892
|
}
|
|
4854
4893
|
};
|
|
@@ -4856,9 +4895,10 @@ var bullmq = {
|
|
|
4856
4895
|
// src/registry/workers.ts
|
|
4857
4896
|
var fs3 = __toESM(require("fs"), 1);
|
|
4858
4897
|
var import_path = __toESM(require("path"), 1);
|
|
4898
|
+
var import_api3 = require("@opentelemetry/api");
|
|
4859
4899
|
var defaultLogsDir = import_path.default.join(process.cwd(), "logs");
|
|
4860
4900
|
var redisConnection;
|
|
4861
|
-
var createWorkers = async (queues2, contexts, _logsDir) => {
|
|
4901
|
+
var createWorkers = async (queues2, logger, contexts, _logsDir, tracer) => {
|
|
4862
4902
|
if (!redisServer.host || !redisServer.port) {
|
|
4863
4903
|
console.error("[EXULU] you are trying to start worker, but no redis server is configured in the environment.");
|
|
4864
4904
|
throw new Error("No redis server configured in the environment, so cannot start worker.");
|
|
@@ -4872,87 +4912,33 @@ var createWorkers = async (queues2, contexts, _logsDir) => {
|
|
|
4872
4912
|
const logsDir = _logsDir || defaultLogsDir;
|
|
4873
4913
|
const workers = queues2.map((queue) => {
|
|
4874
4914
|
console.log(`[EXULU] creating worker for queue ${queue}.`);
|
|
4875
|
-
const worker = new
|
|
4915
|
+
const worker = new import_bullmq5.Worker(
|
|
4876
4916
|
`${queue}`,
|
|
4877
4917
|
async (bullmqJob) => {
|
|
4918
|
+
const logger2 = new ExuluLogger(bullmqJob, logsDir);
|
|
4878
4919
|
const { db: db3 } = await postgresClient();
|
|
4879
4920
|
try {
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
}
|
|
4885
|
-
const context = contexts.find((context2) => context2.id === bullmqJob.data.context);
|
|
4921
|
+
const data = bullmqJob.data;
|
|
4922
|
+
bullmq.validate(bullmqJob.id, data);
|
|
4923
|
+
if (data.type === "embedder") {
|
|
4924
|
+
const context = contexts.find((context2) => context2.id === data.context);
|
|
4886
4925
|
if (!context) {
|
|
4887
|
-
throw new Error(`Context ${
|
|
4926
|
+
throw new Error(`Context ${data.context} not found in the registry.`);
|
|
4888
4927
|
}
|
|
4889
|
-
if (!
|
|
4928
|
+
if (!data.embedder) {
|
|
4890
4929
|
throw new Error(`No embedder set for embedder job.`);
|
|
4891
4930
|
}
|
|
4892
|
-
const embedder = contexts.find((context2) => context2.embedder?.id ===
|
|
4931
|
+
const embedder = contexts.find((context2) => context2.embedder?.id === data.embedder);
|
|
4893
4932
|
if (!embedder) {
|
|
4894
|
-
throw new Error(`Embedder ${
|
|
4895
|
-
}
|
|
4896
|
-
if (!bullmqJob.data.source) {
|
|
4897
|
-
throw new Error("No source set for embedder job.");
|
|
4898
|
-
}
|
|
4899
|
-
const source = context.sources.get(bullmqJob.data.source);
|
|
4900
|
-
if (!source) {
|
|
4901
|
-
throw new Error(`Source ${bullmqJob.data.source} not found in the registry.`);
|
|
4902
|
-
}
|
|
4903
|
-
if (!bullmqJob.data.updater) {
|
|
4904
|
-
throw new Error("No updater set for embedder job.");
|
|
4933
|
+
throw new Error(`Embedder ${data.embedder} not found in the registry.`);
|
|
4905
4934
|
}
|
|
4906
|
-
const
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
}
|
|
4910
|
-
if (!bullmqJob.data.documents) {
|
|
4911
|
-
throw new Error("No input documents set for embedder job.");
|
|
4912
|
-
}
|
|
4913
|
-
if (!Array.isArray(bullmqJob.data.documents)) {
|
|
4914
|
-
throw new Error("Input documents must be an array.");
|
|
4915
|
-
}
|
|
4916
|
-
const result = await embedder.upsert(bullmqJob.data.context, bullmqJob.data.documents, {
|
|
4917
|
-
label: context.name,
|
|
4918
|
-
trigger: bullmqJob.data.trigger || "unknown"
|
|
4935
|
+
const result = await context.createAndUpsertEmbeddings(data.inputs, data.user, {
|
|
4936
|
+
label: embedder.name,
|
|
4937
|
+
trigger: data.trigger
|
|
4919
4938
|
});
|
|
4920
|
-
const mongoRecord = await db3.from("jobs").where({ redis: bullmqJob.id }).first();
|
|
4921
|
-
if (!mongoRecord) {
|
|
4922
|
-
throw new Error("Job not found in the database.");
|
|
4923
|
-
}
|
|
4924
|
-
const finishedAt = /* @__PURE__ */ new Date();
|
|
4925
|
-
const duration = (finishedAt.getTime() - new Date(mongoRecord.createdAt).getTime()) / 1e3;
|
|
4926
|
-
await db3.from("jobs").where({ redis: bullmqJob.id }).update({
|
|
4927
|
-
status: "completed",
|
|
4928
|
-
finishedAt,
|
|
4929
|
-
duration,
|
|
4930
|
-
result: JSON.stringify(result)
|
|
4931
|
-
});
|
|
4932
|
-
await db3.from((void 0).getTableName()).where({ id: result[0].id }).update({
|
|
4933
|
-
embeddings_updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4934
|
-
}).returning("id");
|
|
4935
4939
|
return result;
|
|
4936
4940
|
}
|
|
4937
4941
|
if (bullmqJob.data.type === "workflow") {
|
|
4938
|
-
const workflow = workflows.find((workflow2) => workflow2.id === bullmqJob.data.workflow);
|
|
4939
|
-
if (!workflow) {
|
|
4940
|
-
throw new Error(`Workflow ${bullmqJob.data.workflow} not found in the registry.`);
|
|
4941
|
-
}
|
|
4942
|
-
const exuluJob = await db3.from("jobs").where({ redis: bullmqJob.id }).first();
|
|
4943
|
-
if (!exuluJob) {
|
|
4944
|
-
throw new Error("Job not found in the database.");
|
|
4945
|
-
}
|
|
4946
|
-
const result = await bullmq.process.workflow(bullmqJob, exuluJob, workflow, logsDir);
|
|
4947
|
-
const finishedAt = /* @__PURE__ */ new Date();
|
|
4948
|
-
const duration = (finishedAt.getTime() - new Date(exuluJob.createdAt).getTime()) / 1e3;
|
|
4949
|
-
await db3.from("jobs").where({ redis: bullmqJob.id }).update({
|
|
4950
|
-
status: "completed",
|
|
4951
|
-
finishedAt,
|
|
4952
|
-
duration,
|
|
4953
|
-
result: JSON.stringify(result)
|
|
4954
|
-
});
|
|
4955
|
-
return result;
|
|
4956
4942
|
}
|
|
4957
4943
|
} catch (error) {
|
|
4958
4944
|
await db3.from("jobs").where({ redis: bullmqJob.id }).update({
|
|
@@ -4984,7 +4970,7 @@ var createWorkers = async (queues2, contexts, _logsDir) => {
|
|
|
4984
4970
|
return workers;
|
|
4985
4971
|
};
|
|
4986
4972
|
var createLogsCleanerWorker = (logsDir) => {
|
|
4987
|
-
const logsCleaner = new
|
|
4973
|
+
const logsCleaner = new import_bullmq5.Worker(
|
|
4988
4974
|
global_queues.logs_cleaner,
|
|
4989
4975
|
async (job) => {
|
|
4990
4976
|
console.log(`[EXULU] recurring job ${job.id}.`);
|
|
@@ -5022,6 +5008,7 @@ var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamable
|
|
|
5022
5008
|
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
5023
5009
|
var import_zod3 = require("zod");
|
|
5024
5010
|
var import_express6 = require("express");
|
|
5011
|
+
var import_api4 = require("@opentelemetry/api");
|
|
5025
5012
|
var SESSION_ID_HEADER = "mcp-session-id";
|
|
5026
5013
|
var ExuluMCP = class {
|
|
5027
5014
|
server;
|
|
@@ -5029,7 +5016,7 @@ var ExuluMCP = class {
|
|
|
5029
5016
|
express;
|
|
5030
5017
|
constructor() {
|
|
5031
5018
|
}
|
|
5032
|
-
create = async ({ express: express3, contexts, agents, config, tools }) => {
|
|
5019
|
+
create = async ({ express: express3, contexts, agents, config, tools, tracer, logger }) => {
|
|
5033
5020
|
this.express = express3;
|
|
5034
5021
|
if (!this.server) {
|
|
5035
5022
|
console.log("[EXULU] Creating MCP server.");
|
|
@@ -5207,6 +5194,38 @@ var defaultAgent = new ExuluAgent({
|
|
|
5207
5194
|
}
|
|
5208
5195
|
});
|
|
5209
5196
|
|
|
5197
|
+
// src/registry/index.ts
|
|
5198
|
+
var import_api5 = require("@opentelemetry/api");
|
|
5199
|
+
|
|
5200
|
+
// src/registry/logger.ts
|
|
5201
|
+
var import_winston_transport = require("@opentelemetry/winston-transport");
|
|
5202
|
+
var import_winston = __toESM(require("winston"), 1);
|
|
5203
|
+
var createLogger = ({
|
|
5204
|
+
enableOtel
|
|
5205
|
+
}) => {
|
|
5206
|
+
const logger = import_winston.default.createLogger({
|
|
5207
|
+
level: "debug",
|
|
5208
|
+
format: import_winston.default.format.combine(
|
|
5209
|
+
import_winston.default.format.timestamp(),
|
|
5210
|
+
import_winston.default.format.errors({
|
|
5211
|
+
stack: true
|
|
5212
|
+
}),
|
|
5213
|
+
import_winston.default.format.metadata(),
|
|
5214
|
+
import_winston.default.format.json()
|
|
5215
|
+
),
|
|
5216
|
+
defaultMeta: {
|
|
5217
|
+
service: "Test-Exulu",
|
|
5218
|
+
environment: process.env.NODE_ENV || "development"
|
|
5219
|
+
},
|
|
5220
|
+
transports: [
|
|
5221
|
+
new import_winston.default.transports.Console(),
|
|
5222
|
+
...enableOtel ? [new import_winston_transport.OpenTelemetryTransportV3()] : []
|
|
5223
|
+
]
|
|
5224
|
+
});
|
|
5225
|
+
return logger;
|
|
5226
|
+
};
|
|
5227
|
+
var logger_default = createLogger;
|
|
5228
|
+
|
|
5210
5229
|
// src/registry/index.ts
|
|
5211
5230
|
var ExuluApp = class {
|
|
5212
5231
|
_agents = [];
|
|
@@ -5273,10 +5292,20 @@ var ExuluApp = class {
|
|
|
5273
5292
|
bullmq = {
|
|
5274
5293
|
workers: {
|
|
5275
5294
|
create: async () => {
|
|
5295
|
+
let tracer;
|
|
5296
|
+
if (this._config?.telemetry?.enabled) {
|
|
5297
|
+
console.log("[EXULU] telemetry enabled");
|
|
5298
|
+
tracer = import_api5.trace.getTracer("exulu", "1.0.0");
|
|
5299
|
+
}
|
|
5300
|
+
const logger = logger_default({
|
|
5301
|
+
enableOtel: this._config?.workers?.telemetry?.enabled ?? false
|
|
5302
|
+
});
|
|
5276
5303
|
return await createWorkers(
|
|
5277
5304
|
this._queues,
|
|
5305
|
+
logger,
|
|
5278
5306
|
Object.values(this._contexts ?? {}),
|
|
5279
|
-
this._config?.workers?.logsDir
|
|
5307
|
+
this._config?.workers?.logsDir,
|
|
5308
|
+
tracer
|
|
5280
5309
|
);
|
|
5281
5310
|
}
|
|
5282
5311
|
}
|
|
@@ -5288,11 +5317,22 @@ var ExuluApp = class {
|
|
|
5288
5317
|
throw new Error("Express app not initialized");
|
|
5289
5318
|
}
|
|
5290
5319
|
const app = this._expressApp;
|
|
5320
|
+
let tracer;
|
|
5321
|
+
if (this._config?.telemetry?.enabled) {
|
|
5322
|
+
console.log("[EXULU] telemetry enabled");
|
|
5323
|
+
tracer = import_api5.trace.getTracer("exulu", "1.0.0");
|
|
5324
|
+
}
|
|
5325
|
+
const logger = logger_default({
|
|
5326
|
+
enableOtel: this._config?.telemetry?.enabled ?? false
|
|
5327
|
+
});
|
|
5291
5328
|
await createExpressRoutes(
|
|
5292
5329
|
app,
|
|
5330
|
+
logger,
|
|
5293
5331
|
this._agents,
|
|
5294
5332
|
this._tools,
|
|
5295
|
-
Object.values(this._contexts ?? {})
|
|
5333
|
+
Object.values(this._contexts ?? {}),
|
|
5334
|
+
this._config,
|
|
5335
|
+
tracer
|
|
5296
5336
|
);
|
|
5297
5337
|
if (this._config?.MCP.enabled) {
|
|
5298
5338
|
const mcp = new ExuluMCP();
|
|
@@ -5301,7 +5341,9 @@ var ExuluApp = class {
|
|
|
5301
5341
|
contexts: this._contexts,
|
|
5302
5342
|
agents: this._agents,
|
|
5303
5343
|
config: this._config,
|
|
5304
|
-
tools: this._tools
|
|
5344
|
+
tools: this._tools,
|
|
5345
|
+
tracer,
|
|
5346
|
+
logger
|
|
5305
5347
|
});
|
|
5306
5348
|
await mcp.connect();
|
|
5307
5349
|
}
|
|
@@ -6714,6 +6756,50 @@ var execute = async () => {
|
|
|
6714
6756
|
return;
|
|
6715
6757
|
};
|
|
6716
6758
|
|
|
6759
|
+
// src/registry/otel.ts
|
|
6760
|
+
var import_process = __toESM(require("process"), 1);
|
|
6761
|
+
var import_sdk_node = require("@opentelemetry/sdk-node");
|
|
6762
|
+
var import_auto_instrumentations_node = require("@opentelemetry/auto-instrumentations-node");
|
|
6763
|
+
var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
|
|
6764
|
+
var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
|
|
6765
|
+
var import_resources = require("@opentelemetry/resources");
|
|
6766
|
+
var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
6767
|
+
var import_sdk_logs = require("@opentelemetry/sdk-logs");
|
|
6768
|
+
var create = ({
|
|
6769
|
+
SIGNOZ_ACCESS_TOKEN,
|
|
6770
|
+
SIGNOZ_TRACES_URL,
|
|
6771
|
+
SIGNOZ_LOGS_URL
|
|
6772
|
+
}) => {
|
|
6773
|
+
console.log("SIGNOZ_ACCESS_TOKEN", SIGNOZ_ACCESS_TOKEN);
|
|
6774
|
+
console.log("SIGNOZ_TRACES_URL", SIGNOZ_TRACES_URL);
|
|
6775
|
+
console.log("SIGNOZ_LOGS_URL", SIGNOZ_LOGS_URL);
|
|
6776
|
+
const exporterOptions = {
|
|
6777
|
+
url: SIGNOZ_TRACES_URL,
|
|
6778
|
+
headers: {
|
|
6779
|
+
"signoz-access-token": SIGNOZ_ACCESS_TOKEN
|
|
6780
|
+
}
|
|
6781
|
+
};
|
|
6782
|
+
const traceExporter = new import_exporter_trace_otlp_http.OTLPTraceExporter(exporterOptions);
|
|
6783
|
+
const logExporter = new import_exporter_logs_otlp_http.OTLPLogExporter({
|
|
6784
|
+
url: SIGNOZ_LOGS_URL,
|
|
6785
|
+
headers: {
|
|
6786
|
+
"signoz-access-token": SIGNOZ_ACCESS_TOKEN
|
|
6787
|
+
}
|
|
6788
|
+
});
|
|
6789
|
+
const sdk = new import_sdk_node.NodeSDK({
|
|
6790
|
+
traceExporter,
|
|
6791
|
+
logRecordProcessors: [new import_sdk_logs.BatchLogRecordProcessor(logExporter)],
|
|
6792
|
+
instrumentations: [(0, import_auto_instrumentations_node.getNodeAutoInstrumentations)()],
|
|
6793
|
+
resource: (0, import_resources.resourceFromAttributes)({
|
|
6794
|
+
[import_semantic_conventions.ATTR_SERVICE_NAME]: "Test-Exulu"
|
|
6795
|
+
})
|
|
6796
|
+
});
|
|
6797
|
+
import_process.default.on("SIGTERM", () => {
|
|
6798
|
+
sdk.shutdown().then(() => console.log("Tracing terminated")).catch((error) => console.log("Error terminating tracing", error)).finally(() => import_process.default.exit(0));
|
|
6799
|
+
});
|
|
6800
|
+
return sdk;
|
|
6801
|
+
};
|
|
6802
|
+
|
|
6717
6803
|
// types/enums/jobs.ts
|
|
6718
6804
|
var JOB_STATUS_ENUM = {
|
|
6719
6805
|
completed: "completed",
|
|
@@ -6732,6 +6818,19 @@ var ExuluJobs = {
|
|
|
6732
6818
|
validate: validateJob
|
|
6733
6819
|
}
|
|
6734
6820
|
};
|
|
6821
|
+
var ExuluOtel = {
|
|
6822
|
+
create: ({
|
|
6823
|
+
SIGNOZ_ACCESS_TOKEN,
|
|
6824
|
+
SIGNOZ_TRACES_URL,
|
|
6825
|
+
SIGNOZ_LOGS_URL
|
|
6826
|
+
}) => {
|
|
6827
|
+
return create({
|
|
6828
|
+
SIGNOZ_ACCESS_TOKEN,
|
|
6829
|
+
SIGNOZ_TRACES_URL,
|
|
6830
|
+
SIGNOZ_LOGS_URL
|
|
6831
|
+
});
|
|
6832
|
+
}
|
|
6833
|
+
};
|
|
6735
6834
|
var db2 = {
|
|
6736
6835
|
init: async () => {
|
|
6737
6836
|
await execute();
|
|
@@ -6764,6 +6863,7 @@ var ExuluChunkers = {
|
|
|
6764
6863
|
ExuluEval,
|
|
6765
6864
|
ExuluJobs,
|
|
6766
6865
|
ExuluLogger,
|
|
6866
|
+
ExuluOtel,
|
|
6767
6867
|
ExuluQueues,
|
|
6768
6868
|
ExuluSource,
|
|
6769
6869
|
ExuluTool,
|