@exulu/backend 0.3.13 → 1.2.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/.github/workflows/release.yml +38 -0
- package/.husky/commit-msg +1 -0
- package/CHANGELOG.md +45 -0
- package/README.md +152 -47
- package/commitlint.config.js +4 -0
- package/dist/index.cjs +799 -459
- package/dist/index.d.cts +46 -42
- package/dist/index.d.ts +46 -42
- package/dist/index.js +799 -458
- package/package.json +98 -88
- package/release.config.cjs +9 -0
- package/types/models/user.ts +1 -0
- package/git-conventional-commits.yaml +0 -43
- package/types/models/embedder-backend.ts +0 -15
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,6 @@ __export(index_exports, {
|
|
|
36
36
|
ExuluApp: () => ExuluApp,
|
|
37
37
|
ExuluAuthentication: () => authentication,
|
|
38
38
|
ExuluChunkers: () => ExuluChunkers,
|
|
39
|
-
ExuluCli: () => cli_default,
|
|
40
39
|
ExuluContext: () => ExuluContext,
|
|
41
40
|
ExuluDatabase: () => ExuluDatabase,
|
|
42
41
|
ExuluEmbedder: () => ExuluEmbedder,
|
|
@@ -146,6 +145,47 @@ async function postgresClient() {
|
|
|
146
145
|
}
|
|
147
146
|
|
|
148
147
|
// src/postgres/core-schema.ts
|
|
148
|
+
var agentMessagesSchema = {
|
|
149
|
+
name: {
|
|
150
|
+
plural: "agent_messages",
|
|
151
|
+
singular: "agent_message"
|
|
152
|
+
},
|
|
153
|
+
fields: [
|
|
154
|
+
{
|
|
155
|
+
name: "content",
|
|
156
|
+
type: "text"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: "title",
|
|
160
|
+
type: "text"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: "session",
|
|
164
|
+
type: "text"
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
};
|
|
168
|
+
var agentSessionsSchema = {
|
|
169
|
+
name: {
|
|
170
|
+
plural: "agent_sessions",
|
|
171
|
+
singular: "agent_session"
|
|
172
|
+
},
|
|
173
|
+
fields: [
|
|
174
|
+
{
|
|
175
|
+
name: "agent",
|
|
176
|
+
type: "uuid"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: "user",
|
|
180
|
+
// next auth stores users with id type SERIAL, so we need to use number
|
|
181
|
+
type: "number"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: "title",
|
|
185
|
+
type: "text"
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
};
|
|
149
189
|
var usersSchema = {
|
|
150
190
|
name: {
|
|
151
191
|
plural: "users",
|
|
@@ -203,14 +243,13 @@ var usersSchema = {
|
|
|
203
243
|
name: "last_used",
|
|
204
244
|
type: "date"
|
|
205
245
|
},
|
|
246
|
+
{
|
|
247
|
+
name: "anthropic_token",
|
|
248
|
+
type: "text"
|
|
249
|
+
},
|
|
206
250
|
{
|
|
207
251
|
name: "role",
|
|
208
|
-
type: "
|
|
209
|
-
references: {
|
|
210
|
-
table: "roles",
|
|
211
|
-
field: "id",
|
|
212
|
-
onDelete: "CASCADE"
|
|
213
|
-
}
|
|
252
|
+
type: "uuid"
|
|
214
253
|
}
|
|
215
254
|
]
|
|
216
255
|
};
|
|
@@ -256,10 +295,6 @@ var statisticsSchema = {
|
|
|
256
295
|
{
|
|
257
296
|
name: "total",
|
|
258
297
|
type: "number"
|
|
259
|
-
},
|
|
260
|
-
{
|
|
261
|
-
name: "timeseries",
|
|
262
|
-
type: "json"
|
|
263
298
|
}
|
|
264
299
|
]
|
|
265
300
|
};
|
|
@@ -315,11 +350,11 @@ var evalResultsSchema = {
|
|
|
315
350
|
},
|
|
316
351
|
{
|
|
317
352
|
name: "agent_id",
|
|
318
|
-
type: "
|
|
353
|
+
type: "uuid"
|
|
319
354
|
},
|
|
320
355
|
{
|
|
321
356
|
name: "workflow_id",
|
|
322
|
-
type: "
|
|
357
|
+
type: "uuid"
|
|
323
358
|
},
|
|
324
359
|
{
|
|
325
360
|
name: "eval_type",
|
|
@@ -335,50 +370,6 @@ var evalResultsSchema = {
|
|
|
335
370
|
}
|
|
336
371
|
]
|
|
337
372
|
};
|
|
338
|
-
var threadsSchema = {
|
|
339
|
-
name: {
|
|
340
|
-
plural: "threads",
|
|
341
|
-
singular: "thread"
|
|
342
|
-
},
|
|
343
|
-
fields: [
|
|
344
|
-
{
|
|
345
|
-
name: "resourceId",
|
|
346
|
-
type: "text"
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
name: "title",
|
|
350
|
-
type: "text"
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
name: "metadata",
|
|
354
|
-
type: "text"
|
|
355
|
-
}
|
|
356
|
-
]
|
|
357
|
-
};
|
|
358
|
-
var messagesSchema = {
|
|
359
|
-
name: {
|
|
360
|
-
plural: "messages",
|
|
361
|
-
singular: "message"
|
|
362
|
-
},
|
|
363
|
-
fields: [
|
|
364
|
-
{
|
|
365
|
-
name: "thread_id",
|
|
366
|
-
type: "text"
|
|
367
|
-
},
|
|
368
|
-
{
|
|
369
|
-
name: "content",
|
|
370
|
-
type: "text"
|
|
371
|
-
},
|
|
372
|
-
{
|
|
373
|
-
name: "role",
|
|
374
|
-
type: "text"
|
|
375
|
-
},
|
|
376
|
-
{
|
|
377
|
-
name: "type",
|
|
378
|
-
type: "text"
|
|
379
|
-
}
|
|
380
|
-
]
|
|
381
|
-
};
|
|
382
373
|
var jobsSchema = {
|
|
383
374
|
name: {
|
|
384
375
|
plural: "jobs",
|
|
@@ -411,19 +402,20 @@ var jobsSchema = {
|
|
|
411
402
|
},
|
|
412
403
|
{
|
|
413
404
|
name: "agent",
|
|
414
|
-
type: "
|
|
405
|
+
type: "uuid"
|
|
415
406
|
},
|
|
416
407
|
{
|
|
417
408
|
name: "workflow",
|
|
418
|
-
type: "
|
|
409
|
+
type: "uuid"
|
|
419
410
|
},
|
|
420
411
|
{
|
|
421
412
|
name: "user",
|
|
422
|
-
type
|
|
413
|
+
// next auth stores users with id type SERIAL, so we need to use number
|
|
414
|
+
type: "number"
|
|
423
415
|
},
|
|
424
416
|
{
|
|
425
417
|
name: "item",
|
|
426
|
-
type: "
|
|
418
|
+
type: "uuid"
|
|
427
419
|
},
|
|
428
420
|
{
|
|
429
421
|
name: "steps",
|
|
@@ -517,7 +509,7 @@ var mapType = (t, type, name, defaultValue) => {
|
|
|
517
509
|
return;
|
|
518
510
|
}
|
|
519
511
|
if (type === "date") {
|
|
520
|
-
t.
|
|
512
|
+
t.timestamp(name);
|
|
521
513
|
return;
|
|
522
514
|
}
|
|
523
515
|
if (type === "uuid") {
|
|
@@ -587,23 +579,44 @@ var generateApiKey = async (name, email) => {
|
|
|
587
579
|
|
|
588
580
|
// src/postgres/init-db.ts
|
|
589
581
|
var up = async function(knex) {
|
|
582
|
+
if (!await knex.schema.hasTable("agent_sessions")) {
|
|
583
|
+
await knex.schema.createTable("agent_sessions", (table) => {
|
|
584
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
585
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
586
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
587
|
+
for (const field of agentSessionsSchema.fields) {
|
|
588
|
+
const { type, name, default: defaultValue } = field;
|
|
589
|
+
if (!type || !name) {
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
if (!await knex.schema.hasTable("agent_messages")) {
|
|
597
|
+
await knex.schema.createTable("agent_messages", (table) => {
|
|
598
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
599
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
600
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
601
|
+
for (const field of agentMessagesSchema.fields) {
|
|
602
|
+
const { type, name, default: defaultValue } = field;
|
|
603
|
+
if (!type || !name) {
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
}
|
|
590
610
|
if (!await knex.schema.hasTable("roles")) {
|
|
591
611
|
await knex.schema.createTable("roles", (table) => {
|
|
592
612
|
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
593
|
-
table.
|
|
594
|
-
table.
|
|
613
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
614
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
595
615
|
for (const field of rolesSchema.fields) {
|
|
596
|
-
const { type, name,
|
|
616
|
+
const { type, name, default: defaultValue } = field;
|
|
597
617
|
if (!type || !name) {
|
|
598
618
|
continue;
|
|
599
619
|
}
|
|
600
|
-
if (type === "reference") {
|
|
601
|
-
if (!references) {
|
|
602
|
-
throw new Error("Field with type reference must have a reference definition.");
|
|
603
|
-
}
|
|
604
|
-
table.uuid(name).references(references.field).inTable(references.table);
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
620
|
mapType(table, type, sanitizeName(name), defaultValue);
|
|
608
621
|
}
|
|
609
622
|
});
|
|
@@ -611,20 +624,13 @@ var up = async function(knex) {
|
|
|
611
624
|
if (!await knex.schema.hasTable("eval_results")) {
|
|
612
625
|
await knex.schema.createTable("eval_results", (table) => {
|
|
613
626
|
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
614
|
-
table.
|
|
615
|
-
table.
|
|
627
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
628
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
616
629
|
for (const field of evalResultsSchema.fields) {
|
|
617
|
-
const { type, name,
|
|
630
|
+
const { type, name, default: defaultValue } = field;
|
|
618
631
|
if (!type || !name) {
|
|
619
632
|
continue;
|
|
620
633
|
}
|
|
621
|
-
if (type === "reference") {
|
|
622
|
-
if (!references) {
|
|
623
|
-
throw new Error("Field with type reference must have a reference definition.");
|
|
624
|
-
}
|
|
625
|
-
table.uuid(name).references(references.field).inTable(references.table);
|
|
626
|
-
return;
|
|
627
|
-
}
|
|
628
634
|
mapType(table, type, sanitizeName(name), defaultValue);
|
|
629
635
|
}
|
|
630
636
|
});
|
|
@@ -632,62 +638,41 @@ var up = async function(knex) {
|
|
|
632
638
|
if (!await knex.schema.hasTable("statistics")) {
|
|
633
639
|
await knex.schema.createTable("statistics", (table) => {
|
|
634
640
|
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
635
|
-
table.
|
|
636
|
-
table.
|
|
641
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
642
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
637
643
|
for (const field of statisticsSchema.fields) {
|
|
638
|
-
const { type, name,
|
|
644
|
+
const { type, name, default: defaultValue } = field;
|
|
639
645
|
if (!type || !name) {
|
|
640
646
|
continue;
|
|
641
647
|
}
|
|
642
|
-
if (type === "reference") {
|
|
643
|
-
if (!references) {
|
|
644
|
-
throw new Error("Field with type reference must have a reference definition.");
|
|
645
|
-
}
|
|
646
|
-
table.uuid(name).references(references.field).inTable(references.table);
|
|
647
|
-
return;
|
|
648
|
-
}
|
|
649
648
|
mapType(table, type, sanitizeName(name), defaultValue);
|
|
650
649
|
}
|
|
651
650
|
});
|
|
652
651
|
}
|
|
653
652
|
if (!await knex.schema.hasTable("jobs")) {
|
|
654
653
|
await knex.schema.createTable("jobs", (table) => {
|
|
655
|
-
table.
|
|
656
|
-
table.
|
|
657
|
-
table.
|
|
654
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
655
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
656
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
658
657
|
for (const field of jobsSchema.fields) {
|
|
659
|
-
const { type, name,
|
|
658
|
+
const { type, name, default: defaultValue } = field;
|
|
660
659
|
if (!type || !name) {
|
|
661
660
|
continue;
|
|
662
661
|
}
|
|
663
|
-
if (type === "reference") {
|
|
664
|
-
if (!references) {
|
|
665
|
-
throw new Error("Field with type reference must have a reference definition.");
|
|
666
|
-
}
|
|
667
|
-
table.uuid(name).references(references.field).inTable(references.table);
|
|
668
|
-
return;
|
|
669
|
-
}
|
|
670
662
|
mapType(table, type, sanitizeName(name), defaultValue);
|
|
671
663
|
}
|
|
672
664
|
});
|
|
673
665
|
}
|
|
674
666
|
if (!await knex.schema.hasTable("agents")) {
|
|
675
667
|
await knex.schema.createTable("agents", (table) => {
|
|
676
|
-
table.
|
|
677
|
-
table.
|
|
678
|
-
table.
|
|
668
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
669
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
670
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
679
671
|
for (const field of agentsSchema.fields) {
|
|
680
|
-
const { type, name,
|
|
672
|
+
const { type, name, default: defaultValue } = field;
|
|
681
673
|
if (!type || !name) {
|
|
682
674
|
continue;
|
|
683
675
|
}
|
|
684
|
-
if (type === "reference") {
|
|
685
|
-
if (!references) {
|
|
686
|
-
throw new Error("Field with type reference must have a reference definition.");
|
|
687
|
-
}
|
|
688
|
-
table.uuid(name).references(references.field).inTable(references.table);
|
|
689
|
-
return;
|
|
690
|
-
}
|
|
691
676
|
mapType(table, type, sanitizeName(name), defaultValue);
|
|
692
677
|
}
|
|
693
678
|
});
|
|
@@ -703,8 +688,8 @@ var up = async function(knex) {
|
|
|
703
688
|
if (!await knex.schema.hasTable("users")) {
|
|
704
689
|
await knex.schema.createTable("users", (table) => {
|
|
705
690
|
table.increments("id").primary();
|
|
706
|
-
table.
|
|
707
|
-
table.
|
|
691
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
692
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
708
693
|
table.string("name", 255);
|
|
709
694
|
table.string("password", 255);
|
|
710
695
|
table.string("email", 255);
|
|
@@ -712,20 +697,13 @@ var up = async function(knex) {
|
|
|
712
697
|
table.text("image");
|
|
713
698
|
for (const field of usersSchema.fields) {
|
|
714
699
|
console.log("[EXULU] field", field);
|
|
715
|
-
const { type, name,
|
|
700
|
+
const { type, name, default: defaultValue } = field;
|
|
716
701
|
if (name === "id" || name === "name" || name === "email" || name === "emailVerified" || name === "image") {
|
|
717
702
|
continue;
|
|
718
703
|
}
|
|
719
704
|
if (!type || !name) {
|
|
720
705
|
continue;
|
|
721
706
|
}
|
|
722
|
-
if (type === "reference") {
|
|
723
|
-
if (!references) {
|
|
724
|
-
throw new Error("Field with type reference must have a reference definition.");
|
|
725
|
-
}
|
|
726
|
-
table.uuid(name).references(references.field).inTable(references.table);
|
|
727
|
-
return;
|
|
728
|
-
}
|
|
729
707
|
mapType(table, type, sanitizeName(name), defaultValue);
|
|
730
708
|
}
|
|
731
709
|
});
|
|
@@ -746,14 +724,6 @@ var up = async function(knex) {
|
|
|
746
724
|
table.text("token_type");
|
|
747
725
|
});
|
|
748
726
|
}
|
|
749
|
-
if (!await knex.schema.hasTable("sessions")) {
|
|
750
|
-
await knex.schema.createTable("sessions", (table) => {
|
|
751
|
-
table.increments("id").primary();
|
|
752
|
-
table.integer("userId").notNullable();
|
|
753
|
-
table.timestamp("expires", { useTz: true }).notNullable();
|
|
754
|
-
table.string("sessionToken", 255).notNullable();
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
727
|
};
|
|
758
728
|
var execute = async () => {
|
|
759
729
|
console.log("[EXULU] Initializing database.");
|
|
@@ -1004,6 +974,35 @@ var ExuluEvalUtils = {
|
|
|
1004
974
|
};
|
|
1005
975
|
|
|
1006
976
|
// src/registry/classes.ts
|
|
977
|
+
function sanitizeToolName(name) {
|
|
978
|
+
if (typeof name !== "string") return "";
|
|
979
|
+
let sanitized = name.replace(/[^a-zA-Z0-9_-]+/g, "_");
|
|
980
|
+
sanitized = sanitized.replace(/^_+|_+$/g, "");
|
|
981
|
+
if (sanitized.length > 128) {
|
|
982
|
+
sanitized = sanitized.substring(0, 128);
|
|
983
|
+
}
|
|
984
|
+
return sanitized;
|
|
985
|
+
}
|
|
986
|
+
var convertToolsArrayToObject = (tools) => {
|
|
987
|
+
if (!tools) return {};
|
|
988
|
+
const sanitizedTools = tools ? tools.map((tool2) => ({
|
|
989
|
+
...tool2,
|
|
990
|
+
name: sanitizeToolName(tool2.name)
|
|
991
|
+
})) : [];
|
|
992
|
+
const askForConfirmation = {
|
|
993
|
+
description: "Ask the user for confirmation.",
|
|
994
|
+
parameters: import_zod2.z.object({
|
|
995
|
+
message: import_zod2.z.string().describe("The message to ask for confirmation.")
|
|
996
|
+
})
|
|
997
|
+
};
|
|
998
|
+
return {
|
|
999
|
+
...sanitizedTools?.reduce(
|
|
1000
|
+
(prev, cur) => ({ ...prev, [cur.name]: cur.tool }),
|
|
1001
|
+
{}
|
|
1002
|
+
),
|
|
1003
|
+
askForConfirmation
|
|
1004
|
+
};
|
|
1005
|
+
};
|
|
1007
1006
|
function generateSlug(name) {
|
|
1008
1007
|
const normalized = name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "");
|
|
1009
1008
|
const lowercase = normalized.toLowerCase();
|
|
@@ -1030,54 +1029,119 @@ var ExuluAgent = class {
|
|
|
1030
1029
|
name;
|
|
1031
1030
|
description = "";
|
|
1032
1031
|
slug = "";
|
|
1032
|
+
type;
|
|
1033
1033
|
streaming = false;
|
|
1034
1034
|
rateLimit;
|
|
1035
1035
|
config;
|
|
1036
1036
|
// private memory: Memory | undefined; // TODO do own implementation
|
|
1037
|
-
tools;
|
|
1038
1037
|
evals;
|
|
1039
1038
|
model;
|
|
1040
1039
|
capabilities;
|
|
1041
|
-
constructor({ id, name, description, config, rateLimit, capabilities,
|
|
1040
|
+
constructor({ id, name, description, config, rateLimit, capabilities, type, evals }) {
|
|
1042
1041
|
this.id = id;
|
|
1043
1042
|
this.name = name;
|
|
1044
1043
|
this.evals = evals;
|
|
1045
1044
|
this.description = description;
|
|
1046
1045
|
this.rateLimit = rateLimit;
|
|
1047
|
-
this.tools = tools;
|
|
1048
1046
|
this.config = config;
|
|
1049
|
-
this.
|
|
1047
|
+
this.type = type;
|
|
1048
|
+
this.capabilities = capabilities || {
|
|
1049
|
+
images: [],
|
|
1050
|
+
files: [],
|
|
1051
|
+
audio: [],
|
|
1052
|
+
video: []
|
|
1053
|
+
};
|
|
1050
1054
|
this.slug = `/agents/${generateSlug(this.name)}/run`;
|
|
1051
|
-
this.model = this.config
|
|
1055
|
+
this.model = this.config?.model;
|
|
1052
1056
|
}
|
|
1053
|
-
|
|
1057
|
+
// Exports the agent as a tool that can be used by another agent
|
|
1058
|
+
// todo test this
|
|
1059
|
+
tool = () => {
|
|
1060
|
+
return new ExuluTool({
|
|
1061
|
+
id: this.id,
|
|
1062
|
+
name: `${this.name} agent`,
|
|
1063
|
+
type: "agent",
|
|
1064
|
+
inputSchema: import_zod2.z.object({
|
|
1065
|
+
prompt: import_zod2.z.string()
|
|
1066
|
+
}),
|
|
1067
|
+
description: `A function that calls an AI agent named: ${this.name}. The agent does the following: ${this.description}.`,
|
|
1068
|
+
execute: async ({ prompt }) => {
|
|
1069
|
+
return await this.generateSync({
|
|
1070
|
+
prompt,
|
|
1071
|
+
statistics: {
|
|
1072
|
+
label: "",
|
|
1073
|
+
trigger: "tool"
|
|
1074
|
+
}
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
};
|
|
1079
|
+
generateSync = async ({ messages, prompt, tools, statistics }) => {
|
|
1054
1080
|
if (!this.model) {
|
|
1055
1081
|
throw new Error("Model is required for streaming.");
|
|
1056
1082
|
}
|
|
1057
|
-
if (this.config
|
|
1058
|
-
|
|
1059
|
-
}
|
|
1060
|
-
const { object } = await (0, import_ai.generateObject)({
|
|
1061
|
-
model: this.model,
|
|
1062
|
-
schema: this.config.outputSchema,
|
|
1063
|
-
prompt
|
|
1064
|
-
});
|
|
1065
|
-
return object;
|
|
1083
|
+
if (!this.config) {
|
|
1084
|
+
throw new Error("Config is required for generating.");
|
|
1066
1085
|
}
|
|
1067
|
-
if (
|
|
1068
|
-
|
|
1069
|
-
model: this.model,
|
|
1070
|
-
prompt
|
|
1071
|
-
});
|
|
1072
|
-
const text2 = await result.text;
|
|
1073
|
-
return text2;
|
|
1086
|
+
if (prompt && messages) {
|
|
1087
|
+
throw new Error("Prompt and messages cannot be provided at the same time.");
|
|
1074
1088
|
}
|
|
1075
1089
|
const { text } = await (0, import_ai.generateText)({
|
|
1076
1090
|
model: this.model,
|
|
1077
|
-
|
|
1091
|
+
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.",
|
|
1092
|
+
messages,
|
|
1093
|
+
prompt,
|
|
1094
|
+
maxRetries: 2,
|
|
1095
|
+
tools: convertToolsArrayToObject(tools),
|
|
1096
|
+
maxSteps: 5
|
|
1078
1097
|
});
|
|
1098
|
+
if (statistics) {
|
|
1099
|
+
await updateStatistic({
|
|
1100
|
+
name: "count",
|
|
1101
|
+
label: statistics.label,
|
|
1102
|
+
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
1103
|
+
trigger: statistics.trigger,
|
|
1104
|
+
count: 1
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1079
1107
|
return text;
|
|
1080
1108
|
};
|
|
1109
|
+
generateStream = ({ messages, prompt, tools, statistics }) => {
|
|
1110
|
+
if (!this.model) {
|
|
1111
|
+
throw new Error("Model is required for streaming.");
|
|
1112
|
+
}
|
|
1113
|
+
if (!this.config) {
|
|
1114
|
+
throw new Error("Config is required for generating.");
|
|
1115
|
+
}
|
|
1116
|
+
if (prompt && messages) {
|
|
1117
|
+
throw new Error("Prompt and messages cannot be provided at the same time.");
|
|
1118
|
+
}
|
|
1119
|
+
return (0, import_ai.streamText)({
|
|
1120
|
+
model: this.model,
|
|
1121
|
+
messages,
|
|
1122
|
+
prompt,
|
|
1123
|
+
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.",
|
|
1124
|
+
maxRetries: 2,
|
|
1125
|
+
tools: convertToolsArrayToObject(tools),
|
|
1126
|
+
maxSteps: 5,
|
|
1127
|
+
onError: (error) => console.error("[EXULU] chat stream error.", error),
|
|
1128
|
+
onFinish: async ({ response, usage }) => {
|
|
1129
|
+
console.info(
|
|
1130
|
+
"[EXULU] chat stream finished.",
|
|
1131
|
+
usage
|
|
1132
|
+
);
|
|
1133
|
+
if (statistics) {
|
|
1134
|
+
await updateStatistic({
|
|
1135
|
+
name: "count",
|
|
1136
|
+
label: statistics.label,
|
|
1137
|
+
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
1138
|
+
trigger: statistics.trigger,
|
|
1139
|
+
count: 1
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
});
|
|
1144
|
+
};
|
|
1081
1145
|
};
|
|
1082
1146
|
var ExuluEmbedder = class {
|
|
1083
1147
|
id;
|
|
@@ -1100,6 +1164,13 @@ var ExuluEmbedder = class {
|
|
|
1100
1164
|
}
|
|
1101
1165
|
async generateFromQuery(query, statistics) {
|
|
1102
1166
|
if (statistics) {
|
|
1167
|
+
await updateStatistic({
|
|
1168
|
+
name: "count",
|
|
1169
|
+
label: statistics.label,
|
|
1170
|
+
type: STATISTICS_TYPE_ENUM.EMBEDDER_GENERATE,
|
|
1171
|
+
trigger: statistics.trigger,
|
|
1172
|
+
count: 1
|
|
1173
|
+
});
|
|
1103
1174
|
}
|
|
1104
1175
|
return await this.generateEmbeddings({
|
|
1105
1176
|
item: {
|
|
@@ -1113,6 +1184,13 @@ var ExuluEmbedder = class {
|
|
|
1113
1184
|
}
|
|
1114
1185
|
async generateFromDocument(input, statistics) {
|
|
1115
1186
|
if (statistics) {
|
|
1187
|
+
await updateStatistic({
|
|
1188
|
+
name: "count",
|
|
1189
|
+
label: statistics.label,
|
|
1190
|
+
type: STATISTICS_TYPE_ENUM.EMBEDDER_GENERATE,
|
|
1191
|
+
trigger: statistics.trigger,
|
|
1192
|
+
count: 1
|
|
1193
|
+
});
|
|
1116
1194
|
}
|
|
1117
1195
|
if (!this.chunker) {
|
|
1118
1196
|
throw new Error("Chunker not found for embedder " + this.name);
|
|
@@ -1301,9 +1379,8 @@ var ExuluEval = class {
|
|
|
1301
1379
|
if (!data.prompt) {
|
|
1302
1380
|
throw new Error("Prompt is required for running an agent.");
|
|
1303
1381
|
}
|
|
1304
|
-
const result = await runner.agent.
|
|
1305
|
-
prompt: data.prompt
|
|
1306
|
-
stream: false
|
|
1382
|
+
const result = await runner.agent.generateSync({
|
|
1383
|
+
prompt: data.prompt
|
|
1307
1384
|
});
|
|
1308
1385
|
data.result = result;
|
|
1309
1386
|
}
|
|
@@ -1398,18 +1475,18 @@ var ExuluTool = class {
|
|
|
1398
1475
|
id;
|
|
1399
1476
|
name;
|
|
1400
1477
|
description;
|
|
1401
|
-
|
|
1478
|
+
inputSchema;
|
|
1402
1479
|
type;
|
|
1403
1480
|
tool;
|
|
1404
|
-
constructor({ id, name, description,
|
|
1481
|
+
constructor({ id, name, description, inputSchema, type, execute: execute2 }) {
|
|
1405
1482
|
this.id = id;
|
|
1406
1483
|
this.name = name;
|
|
1407
1484
|
this.description = description;
|
|
1408
|
-
this.
|
|
1485
|
+
this.inputSchema = inputSchema;
|
|
1409
1486
|
this.type = type;
|
|
1410
1487
|
this.tool = (0, import_ai.tool)({
|
|
1411
1488
|
description,
|
|
1412
|
-
parameters,
|
|
1489
|
+
parameters: inputSchema || import_zod2.z.object({}),
|
|
1413
1490
|
execute: execute2
|
|
1414
1491
|
});
|
|
1415
1492
|
}
|
|
@@ -1465,7 +1542,7 @@ var ExuluContext = class {
|
|
|
1465
1542
|
}
|
|
1466
1543
|
const { db: db2 } = await postgresClient();
|
|
1467
1544
|
Object.keys(item).forEach((key) => {
|
|
1468
|
-
if (key === "name" || key === "description" || key === "external_id" || key === "tags" || key === "source" || key === "textLength" || key === "upsert") {
|
|
1545
|
+
if (key === "name" || key === "description" || key === "external_id" || key === "tags" || key === "source" || key === "textLength" || key === "upsert" || key === "archived") {
|
|
1469
1546
|
return;
|
|
1470
1547
|
}
|
|
1471
1548
|
const field = this.fields.find((field2) => field2.name === key);
|
|
@@ -1512,6 +1589,9 @@ var ExuluContext = class {
|
|
|
1512
1589
|
chunk_index: chunk.index,
|
|
1513
1590
|
embedding: import_knex4.default.toSql(chunk.vector)
|
|
1514
1591
|
})));
|
|
1592
|
+
await db2.from(this.getTableName()).where({ id }).update({
|
|
1593
|
+
embeddings_updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1594
|
+
}).returning("id");
|
|
1515
1595
|
}
|
|
1516
1596
|
return {
|
|
1517
1597
|
id: result[0].id,
|
|
@@ -1541,7 +1621,7 @@ var ExuluContext = class {
|
|
|
1541
1621
|
}
|
|
1542
1622
|
}
|
|
1543
1623
|
Object.keys(item).forEach((key) => {
|
|
1544
|
-
if (key === "name" || key === "description" || key === "external_id" || key === "tags" || key === "source" || key === "textLength" || key === "upsert") {
|
|
1624
|
+
if (key === "name" || key === "description" || key === "external_id" || key === "tags" || key === "source" || key === "textLength" || key === "upsert" || key === "archived") {
|
|
1545
1625
|
return;
|
|
1546
1626
|
}
|
|
1547
1627
|
const field = this.fields.find((field2) => field2.name === key);
|
|
@@ -1592,6 +1672,9 @@ var ExuluContext = class {
|
|
|
1592
1672
|
chunk_index: chunk.index,
|
|
1593
1673
|
embedding: import_knex4.default.toSql(chunk.vector)
|
|
1594
1674
|
})));
|
|
1675
|
+
await db2.from(this.getTableName()).where({ id: result[0].id }).update({
|
|
1676
|
+
embeddings_updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1677
|
+
}).returning("id");
|
|
1595
1678
|
}
|
|
1596
1679
|
return {
|
|
1597
1680
|
id: result[0].id,
|
|
@@ -1601,6 +1684,8 @@ var ExuluContext = class {
|
|
|
1601
1684
|
getItems = async ({
|
|
1602
1685
|
statistics,
|
|
1603
1686
|
limit,
|
|
1687
|
+
sort,
|
|
1688
|
+
order,
|
|
1604
1689
|
page,
|
|
1605
1690
|
name,
|
|
1606
1691
|
archived,
|
|
@@ -1621,6 +1706,9 @@ var ExuluContext = class {
|
|
|
1621
1706
|
const columns = await db2(mainTable).columnInfo();
|
|
1622
1707
|
const totalQuery = db2.count("* as count").from(mainTable).first();
|
|
1623
1708
|
const itemsQuery = db2.select(Object.keys(columns).map((column) => mainTable + "." + column)).from(mainTable).offset(offset).limit(limit);
|
|
1709
|
+
if (sort) {
|
|
1710
|
+
itemsQuery.orderBy(sort, order === "desc" ? "desc" : "asc");
|
|
1711
|
+
}
|
|
1624
1712
|
if (typeof name === "string") {
|
|
1625
1713
|
itemsQuery.whereILike("name", `%${name}%`);
|
|
1626
1714
|
totalQuery.whereILike("name", `%${name}%`);
|
|
@@ -1664,7 +1752,7 @@ var ExuluContext = class {
|
|
|
1664
1752
|
}
|
|
1665
1753
|
itemsQuery.limit(limit * 5);
|
|
1666
1754
|
if (statistics) {
|
|
1667
|
-
updateStatistic({
|
|
1755
|
+
await updateStatistic({
|
|
1668
1756
|
name: "count",
|
|
1669
1757
|
label: statistics.label,
|
|
1670
1758
|
type: STATISTICS_TYPE_ENUM.CONTEXT_RETRIEVE,
|
|
@@ -1797,6 +1885,7 @@ var ExuluContext = class {
|
|
|
1797
1885
|
table.text("external_id");
|
|
1798
1886
|
table.integer("textLength");
|
|
1799
1887
|
table.text("source");
|
|
1888
|
+
table.timestamp("embeddings_updated_at");
|
|
1800
1889
|
for (const field of this.fields) {
|
|
1801
1890
|
const { type, name } = field;
|
|
1802
1891
|
if (!type || !name) {
|
|
@@ -1826,15 +1915,15 @@ var ExuluContext = class {
|
|
|
1826
1915
|
id: this.id,
|
|
1827
1916
|
name: `${this.name} context`,
|
|
1828
1917
|
type: "context",
|
|
1829
|
-
|
|
1918
|
+
inputSchema: import_zod2.z.object({
|
|
1830
1919
|
query: import_zod2.z.string()
|
|
1831
1920
|
}),
|
|
1832
1921
|
description: `Gets information from the context called: ${this.name}. The context description is: ${this.description}.`,
|
|
1833
|
-
execute: async ({
|
|
1922
|
+
execute: async ({ query }) => {
|
|
1834
1923
|
return await this.getItems({
|
|
1835
1924
|
page: 1,
|
|
1836
1925
|
limit: 10,
|
|
1837
|
-
query
|
|
1926
|
+
query,
|
|
1838
1927
|
statistics: {
|
|
1839
1928
|
label: this.name,
|
|
1840
1929
|
trigger: "agent"
|
|
@@ -1883,7 +1972,32 @@ var ExuluSource = class {
|
|
|
1883
1972
|
}
|
|
1884
1973
|
};
|
|
1885
1974
|
var updateStatistic = async (statistic) => {
|
|
1886
|
-
|
|
1975
|
+
const currentDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1976
|
+
const { db: db2 } = await postgresClient();
|
|
1977
|
+
const existing = await db2.from("statistics").where({
|
|
1978
|
+
name: statistic.name,
|
|
1979
|
+
label: statistic.label,
|
|
1980
|
+
type: statistic.type,
|
|
1981
|
+
createdAt: currentDate
|
|
1982
|
+
}).first();
|
|
1983
|
+
if (!existing) {
|
|
1984
|
+
await db2.from("statistics").insert({
|
|
1985
|
+
name: statistic.name,
|
|
1986
|
+
label: statistic.label,
|
|
1987
|
+
type: statistic.type,
|
|
1988
|
+
total: statistic.count ?? 1,
|
|
1989
|
+
createdAt: currentDate
|
|
1990
|
+
});
|
|
1991
|
+
} else {
|
|
1992
|
+
await db2.from("statistics").update({
|
|
1993
|
+
total: db2.raw("total + ?", [statistic.count ?? 1])
|
|
1994
|
+
}).where({
|
|
1995
|
+
name: statistic.name,
|
|
1996
|
+
label: statistic.label,
|
|
1997
|
+
type: statistic.type,
|
|
1998
|
+
createdAt: currentDate
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
1887
2001
|
};
|
|
1888
2002
|
|
|
1889
2003
|
// src/registry/index.ts
|
|
@@ -1983,6 +2097,7 @@ var authentication = async ({
|
|
|
1983
2097
|
}
|
|
1984
2098
|
if (authtoken) {
|
|
1985
2099
|
try {
|
|
2100
|
+
console.log("[EXULU] authtoken", authtoken);
|
|
1986
2101
|
if (!authtoken?.email) {
|
|
1987
2102
|
return {
|
|
1988
2103
|
error: true,
|
|
@@ -2076,8 +2191,7 @@ var requestValidators = {
|
|
|
2076
2191
|
const { db: db2 } = await postgresClient();
|
|
2077
2192
|
let authtoken = null;
|
|
2078
2193
|
if (typeof apikey !== "string") {
|
|
2079
|
-
|
|
2080
|
-
authtoken = await getToken(req.headers["authorization"] ?? "");
|
|
2194
|
+
authtoken = await getToken((req.headers["authorization"] || req.headers["x-api-key"]) ?? "");
|
|
2081
2195
|
}
|
|
2082
2196
|
return await authentication({
|
|
2083
2197
|
authtoken,
|
|
@@ -2270,6 +2384,42 @@ var import_reflect_metadata = require("reflect-metadata");
|
|
|
2270
2384
|
// src/registry/utils/graphql.ts
|
|
2271
2385
|
var import_schema = require("@graphql-tools/schema");
|
|
2272
2386
|
var import_graphql_type_json = __toESM(require("graphql-type-json"), 1);
|
|
2387
|
+
var import_graphql = require("graphql");
|
|
2388
|
+
var import_crypto_js = __toESM(require("crypto-js"), 1);
|
|
2389
|
+
var GraphQLDate = new import_graphql.GraphQLScalarType({
|
|
2390
|
+
name: "Date",
|
|
2391
|
+
description: "Date custom scalar type",
|
|
2392
|
+
serialize(value) {
|
|
2393
|
+
if (value instanceof Date) {
|
|
2394
|
+
return value.toISOString();
|
|
2395
|
+
}
|
|
2396
|
+
if (typeof value === "number") {
|
|
2397
|
+
return new Date(value).toISOString();
|
|
2398
|
+
}
|
|
2399
|
+
if (typeof value === "string") {
|
|
2400
|
+
return new Date(value).toISOString();
|
|
2401
|
+
}
|
|
2402
|
+
return value;
|
|
2403
|
+
},
|
|
2404
|
+
parseValue(value) {
|
|
2405
|
+
if (typeof value === "string") {
|
|
2406
|
+
return new Date(value);
|
|
2407
|
+
}
|
|
2408
|
+
if (typeof value === "number") {
|
|
2409
|
+
return new Date(value);
|
|
2410
|
+
}
|
|
2411
|
+
return value;
|
|
2412
|
+
},
|
|
2413
|
+
parseLiteral(ast) {
|
|
2414
|
+
if (ast.kind === import_graphql.Kind.STRING) {
|
|
2415
|
+
return new Date(ast.value);
|
|
2416
|
+
}
|
|
2417
|
+
if (ast.kind === import_graphql.Kind.INT) {
|
|
2418
|
+
return new Date(parseInt(ast.value, 10));
|
|
2419
|
+
}
|
|
2420
|
+
return null;
|
|
2421
|
+
}
|
|
2422
|
+
});
|
|
2273
2423
|
var map = (field) => {
|
|
2274
2424
|
let type;
|
|
2275
2425
|
switch (field.type) {
|
|
@@ -2289,7 +2439,7 @@ var map = (field) => {
|
|
|
2289
2439
|
type = "JSON";
|
|
2290
2440
|
break;
|
|
2291
2441
|
case "date":
|
|
2292
|
-
type = "
|
|
2442
|
+
type = "Date";
|
|
2293
2443
|
break;
|
|
2294
2444
|
default:
|
|
2295
2445
|
type = "String";
|
|
@@ -2307,8 +2457,8 @@ function createTypeDefs(table) {
|
|
|
2307
2457
|
type ${table.name.singular} {
|
|
2308
2458
|
${fields.join("\n")}
|
|
2309
2459
|
id: ID!
|
|
2310
|
-
createdAt:
|
|
2311
|
-
updatedAt:
|
|
2460
|
+
createdAt: Date!
|
|
2461
|
+
updatedAt: Date!
|
|
2312
2462
|
}
|
|
2313
2463
|
`;
|
|
2314
2464
|
const inputDef = `
|
|
@@ -2334,6 +2484,11 @@ input FilterOperatorString {
|
|
|
2334
2484
|
contains: String
|
|
2335
2485
|
}
|
|
2336
2486
|
|
|
2487
|
+
input FilterOperatorDate {
|
|
2488
|
+
lte: Date
|
|
2489
|
+
gte: Date
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2337
2492
|
input FilterOperatorFloat {
|
|
2338
2493
|
eq: Float
|
|
2339
2494
|
ne: Float
|
|
@@ -2386,8 +2541,10 @@ function createMutations(table) {
|
|
|
2386
2541
|
[`${tableNamePlural}CreateOne`]: async (_, args, context, info) => {
|
|
2387
2542
|
const { db: db2 } = context;
|
|
2388
2543
|
const requestedFields = getRequestedFields(info);
|
|
2544
|
+
let { input } = args;
|
|
2545
|
+
input = encryptSensitiveFields(input);
|
|
2389
2546
|
const results = await db2(tableNamePlural).insert({
|
|
2390
|
-
...
|
|
2547
|
+
...input,
|
|
2391
2548
|
createdAt: /* @__PURE__ */ new Date(),
|
|
2392
2549
|
updatedAt: /* @__PURE__ */ new Date()
|
|
2393
2550
|
}).returning(requestedFields);
|
|
@@ -2395,7 +2552,8 @@ function createMutations(table) {
|
|
|
2395
2552
|
},
|
|
2396
2553
|
[`${tableNamePlural}UpdateOne`]: async (_, args, context, info) => {
|
|
2397
2554
|
const { db: db2 } = context;
|
|
2398
|
-
|
|
2555
|
+
let { where, input } = args;
|
|
2556
|
+
input = encryptSensitiveFields(input);
|
|
2399
2557
|
await db2(tableNamePlural).where(where).update({
|
|
2400
2558
|
...input,
|
|
2401
2559
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -2405,7 +2563,8 @@ function createMutations(table) {
|
|
|
2405
2563
|
return result;
|
|
2406
2564
|
},
|
|
2407
2565
|
[`${tableNamePlural}UpdateOneById`]: async (_, args, context, info) => {
|
|
2408
|
-
|
|
2566
|
+
let { id, input } = args;
|
|
2567
|
+
input = encryptSensitiveFields(input);
|
|
2409
2568
|
const { db: db2 } = context;
|
|
2410
2569
|
await db2(tableNamePlural).where({ id }).update({
|
|
2411
2570
|
...input,
|
|
@@ -2508,12 +2667,44 @@ function createQueries(table) {
|
|
|
2508
2667
|
},
|
|
2509
2668
|
items
|
|
2510
2669
|
};
|
|
2511
|
-
}
|
|
2670
|
+
},
|
|
2671
|
+
// Add jobStatistics query for jobs table
|
|
2672
|
+
...tableNamePlural === "jobs" ? {
|
|
2673
|
+
jobStatistics: async (_, args, context, info) => {
|
|
2674
|
+
const { user, agent, from, to } = args;
|
|
2675
|
+
const { db: db2 } = context;
|
|
2676
|
+
let query = db2("jobs");
|
|
2677
|
+
if (user) {
|
|
2678
|
+
query = query.where("user", user);
|
|
2679
|
+
}
|
|
2680
|
+
if (agent) {
|
|
2681
|
+
query = query.where("agent", agent);
|
|
2682
|
+
}
|
|
2683
|
+
if (from) {
|
|
2684
|
+
query = query.where("createdAt", ">=", from);
|
|
2685
|
+
}
|
|
2686
|
+
if (to) {
|
|
2687
|
+
query = query.where("createdAt", "<=", to);
|
|
2688
|
+
}
|
|
2689
|
+
const completedQuery = query.clone().where("status", "completed");
|
|
2690
|
+
const [{ completedCount }] = await completedQuery.count("* as completedCount");
|
|
2691
|
+
const failedQuery = query.clone().where("status", "failed");
|
|
2692
|
+
const [{ failedCount }] = await failedQuery.count("* as failedCount");
|
|
2693
|
+
const durationQuery = query.clone().where("status", "completed").whereNotNull("duration").select(db2.raw('AVG("duration") as averageDuration'));
|
|
2694
|
+
const [{ averageDuration }] = await durationQuery;
|
|
2695
|
+
return {
|
|
2696
|
+
completedCount: Number(completedCount),
|
|
2697
|
+
failedCount: Number(failedCount),
|
|
2698
|
+
averageDuration: averageDuration ? Number(averageDuration) : 0
|
|
2699
|
+
};
|
|
2700
|
+
}
|
|
2701
|
+
} : {}
|
|
2512
2702
|
};
|
|
2513
2703
|
}
|
|
2514
2704
|
function createSDL(tables) {
|
|
2515
2705
|
let typeDefs = `
|
|
2516
2706
|
scalar JSON
|
|
2707
|
+
scalar Date
|
|
2517
2708
|
|
|
2518
2709
|
type Query {
|
|
2519
2710
|
`;
|
|
@@ -2521,7 +2712,7 @@ function createSDL(tables) {
|
|
|
2521
2712
|
type Mutation {
|
|
2522
2713
|
`;
|
|
2523
2714
|
let modelDefs = "";
|
|
2524
|
-
const resolvers = { JSON: import_graphql_type_json.default, Query: {}, Mutation: {} };
|
|
2715
|
+
const resolvers = { JSON: import_graphql_type_json.default, Date: GraphQLDate, Query: {}, Mutation: {} };
|
|
2525
2716
|
for (const table of tables) {
|
|
2526
2717
|
const tableNamePlural = table.name.plural.toLowerCase();
|
|
2527
2718
|
const tableNameSingular = table.name.singular.toLowerCase();
|
|
@@ -2530,6 +2721,7 @@ function createSDL(tables) {
|
|
|
2530
2721
|
${tableNameSingular}ById(id: ID!): ${tableNameSingular}
|
|
2531
2722
|
${tableNamePlural}Pagination(limit: Int, page: Int, filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingularUpperCaseFirst}PaginationResult
|
|
2532
2723
|
${tableNameSingular}One(filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingular}
|
|
2724
|
+
${tableNamePlural === "jobs" ? `jobStatistics(user: ID, agent: String, from: String, to: String): JobStatistics` : ""}
|
|
2533
2725
|
`;
|
|
2534
2726
|
mutationDefs += `
|
|
2535
2727
|
${tableNamePlural}CreateOne(input: ${tableNameSingular}Input!): ${tableNameSingular}
|
|
@@ -2554,6 +2746,15 @@ type PageInfo {
|
|
|
2554
2746
|
hasNextPage: Boolean!
|
|
2555
2747
|
}
|
|
2556
2748
|
`;
|
|
2749
|
+
if (tableNamePlural === "jobs") {
|
|
2750
|
+
modelDefs += `
|
|
2751
|
+
type JobStatistics {
|
|
2752
|
+
completedCount: Int!
|
|
2753
|
+
failedCount: Int!
|
|
2754
|
+
averageDuration: Float!
|
|
2755
|
+
}
|
|
2756
|
+
`;
|
|
2757
|
+
}
|
|
2557
2758
|
Object.assign(resolvers.Query, createQueries(table));
|
|
2558
2759
|
Object.assign(resolvers.Mutation, createMutations(table));
|
|
2559
2760
|
}
|
|
@@ -2590,6 +2791,15 @@ type PageInfo {
|
|
|
2590
2791
|
console.log("\n");
|
|
2591
2792
|
return schema;
|
|
2592
2793
|
}
|
|
2794
|
+
var sensitiveFields = ["anthropic_token"];
|
|
2795
|
+
var encryptSensitiveFields = (input) => {
|
|
2796
|
+
sensitiveFields.forEach((field) => {
|
|
2797
|
+
if (input[field]) {
|
|
2798
|
+
input[field] = import_crypto_js.default.AES.encrypt(input[field], process.env.NEXTAUTH_SECRET).toString();
|
|
2799
|
+
}
|
|
2800
|
+
});
|
|
2801
|
+
return input;
|
|
2802
|
+
};
|
|
2593
2803
|
|
|
2594
2804
|
// src/registry/routes.ts
|
|
2595
2805
|
var import_express5 = require("@as-integrations/express5");
|
|
@@ -2988,6 +3198,34 @@ var createUppyRoutes = async (app) => {
|
|
|
2988
3198
|
// src/registry/routes.ts
|
|
2989
3199
|
var import_utils2 = require("@apollo/utils.keyvaluecache");
|
|
2990
3200
|
var import_body_parser = __toESM(require("body-parser"), 1);
|
|
3201
|
+
var import_crypto_js2 = __toESM(require("crypto-js"), 1);
|
|
3202
|
+
|
|
3203
|
+
// src/registry/utils/claude-messages.ts
|
|
3204
|
+
var CLAUDE_MESSAGES = {
|
|
3205
|
+
authentication_error: `
|
|
3206
|
+
\x1B[41m -- Authentication error please check your IMP token and try again. --
|
|
3207
|
+
\x1B[0m`,
|
|
3208
|
+
missing_body: `
|
|
3209
|
+
\x1B[41m -- Missing body Anthropic response. --
|
|
3210
|
+
\x1B[0m`,
|
|
3211
|
+
missing_nextauth_secret: `
|
|
3212
|
+
\x1B[41m -- Missing NEXTAUTH_SECRET in environment variables on the server. --
|
|
3213
|
+
\x1B[0m`,
|
|
3214
|
+
not_enabled: `
|
|
3215
|
+
\x1B[31m
|
|
3216
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557
|
|
3217
|
+
\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2588\u2588\u2557\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
|
|
3218
|
+
\u2588\u2588\u2588\u2588\u2588\u2557 \u255A\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
|
|
3219
|
+
\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
|
|
3220
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2554\u255D \u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
|
|
3221
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D
|
|
3222
|
+
Intelligence Management Platform
|
|
3223
|
+
\x1B[0m
|
|
3224
|
+
\x1B[41m -- Your account has not been enabled to use Claude Code, please contact your admin or enable Claude Code in the user settings. --
|
|
3225
|
+
\x1B[0m`
|
|
3226
|
+
};
|
|
3227
|
+
|
|
3228
|
+
// src/registry/routes.ts
|
|
2991
3229
|
var REQUEST_SIZE_LIMIT = "50mb";
|
|
2992
3230
|
var global_queues = {
|
|
2993
3231
|
logs_cleaner: "logs-cleaner"
|
|
@@ -3024,7 +3262,7 @@ var createRecurringJobs = async () => {
|
|
|
3024
3262
|
console.table(recurringJobSchedulersLogs);
|
|
3025
3263
|
return queue;
|
|
3026
3264
|
};
|
|
3027
|
-
var createExpressRoutes = async (app, agents,
|
|
3265
|
+
var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
|
|
3028
3266
|
const routeLogs = [];
|
|
3029
3267
|
var corsOptions = {
|
|
3030
3268
|
origin: "*",
|
|
@@ -3044,6 +3282,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3044
3282
|
\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
|
|
3045
3283
|
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2554\u255D \u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
|
|
3046
3284
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D
|
|
3285
|
+
Intelligence Management Platform
|
|
3047
3286
|
|
|
3048
3287
|
`);
|
|
3049
3288
|
console.log("Agents:");
|
|
@@ -3092,7 +3331,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3092
3331
|
} else {
|
|
3093
3332
|
console.log("===========================", "[EXULU] no redis server configured, not setting up recurring jobs.", "===========================");
|
|
3094
3333
|
}
|
|
3095
|
-
const schema = createSDL([usersSchema, rolesSchema, agentsSchema, jobsSchema, workflowSchema, evalResultsSchema,
|
|
3334
|
+
const schema = createSDL([usersSchema, rolesSchema, agentsSchema, jobsSchema, workflowSchema, evalResultsSchema, agentSessionsSchema, agentMessagesSchema]);
|
|
3096
3335
|
console.log("[EXULU] graphql server");
|
|
3097
3336
|
const server = new import_server3.ApolloServer({
|
|
3098
3337
|
cache: new import_utils2.InMemoryLRUCache(),
|
|
@@ -3120,10 +3359,52 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3120
3359
|
}
|
|
3121
3360
|
})
|
|
3122
3361
|
);
|
|
3123
|
-
app.get(`/
|
|
3362
|
+
app.get(`/providers`, async (req, res) => {
|
|
3363
|
+
const authenticationResult = await requestValidators.authenticate(req);
|
|
3364
|
+
if (!authenticationResult.user?.id) {
|
|
3365
|
+
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
3366
|
+
return;
|
|
3367
|
+
}
|
|
3124
3368
|
res.status(200).json(agents);
|
|
3125
3369
|
});
|
|
3370
|
+
app.get(`/agents`, async (req, res) => {
|
|
3371
|
+
const authenticationResult = await requestValidators.authenticate(req);
|
|
3372
|
+
if (!authenticationResult.user?.id) {
|
|
3373
|
+
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
3374
|
+
return;
|
|
3375
|
+
}
|
|
3376
|
+
const { db: db2 } = await postgresClient();
|
|
3377
|
+
const agentsFromDb = await db2.from("agents").select("*");
|
|
3378
|
+
res.status(200).json(agentsFromDb.map((agent) => {
|
|
3379
|
+
const backend = agents.find((a) => a.id === agent.backend);
|
|
3380
|
+
if (!backend) {
|
|
3381
|
+
return null;
|
|
3382
|
+
}
|
|
3383
|
+
return {
|
|
3384
|
+
name: agent.name,
|
|
3385
|
+
id: agent.id,
|
|
3386
|
+
description: agent.description,
|
|
3387
|
+
provider: backend?.model?.provider,
|
|
3388
|
+
model: backend?.model?.modelId,
|
|
3389
|
+
active: agent.active,
|
|
3390
|
+
public: agent.public,
|
|
3391
|
+
type: agent.type,
|
|
3392
|
+
slug: backend?.slug,
|
|
3393
|
+
rateLimit: backend?.rateLimit,
|
|
3394
|
+
streaming: backend?.streaming,
|
|
3395
|
+
capabilities: backend?.capabilities,
|
|
3396
|
+
// todo add contexts
|
|
3397
|
+
availableTools: tools,
|
|
3398
|
+
enabledTools: agent.tools
|
|
3399
|
+
};
|
|
3400
|
+
}).filter(Boolean));
|
|
3401
|
+
});
|
|
3126
3402
|
app.get(`/agents/:id`, async (req, res) => {
|
|
3403
|
+
const authenticationResult = await requestValidators.authenticate(req);
|
|
3404
|
+
if (!authenticationResult.user?.id) {
|
|
3405
|
+
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
3406
|
+
return;
|
|
3407
|
+
}
|
|
3127
3408
|
const { db: db2 } = await postgresClient();
|
|
3128
3409
|
const id = req.params.id;
|
|
3129
3410
|
if (!id) {
|
|
@@ -3146,6 +3427,8 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3146
3427
|
name: agent.name,
|
|
3147
3428
|
id: agent.id,
|
|
3148
3429
|
description: agent.description,
|
|
3430
|
+
provider: backend?.model?.provider,
|
|
3431
|
+
model: backend?.model?.modelId,
|
|
3149
3432
|
active: agent.active,
|
|
3150
3433
|
public: agent.public,
|
|
3151
3434
|
type: agent.type,
|
|
@@ -3154,7 +3437,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3154
3437
|
streaming: backend?.streaming,
|
|
3155
3438
|
capabilities: backend?.capabilities,
|
|
3156
3439
|
// todo add contexts
|
|
3157
|
-
availableTools:
|
|
3440
|
+
availableTools: tools,
|
|
3158
3441
|
enabledTools: agent.tools
|
|
3159
3442
|
}
|
|
3160
3443
|
});
|
|
@@ -3165,8 +3448,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3165
3448
|
name: tool2.name,
|
|
3166
3449
|
description: tool2.description,
|
|
3167
3450
|
type: tool2.type || "tool",
|
|
3168
|
-
inputSchema: tool2.inputSchema ? (0, import_zodex.zerialize)(tool2.inputSchema) : null
|
|
3169
|
-
outputSchema: tool2.outputSchema ? (0, import_zodex.zerialize)(tool2.outputSchema) : null
|
|
3451
|
+
inputSchema: tool2.inputSchema ? (0, import_zodex.zerialize)(tool2.inputSchema) : null
|
|
3170
3452
|
})));
|
|
3171
3453
|
});
|
|
3172
3454
|
app.get("/tools/:id", async (req, res) => {
|
|
@@ -3284,6 +3566,14 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3284
3566
|
});
|
|
3285
3567
|
return;
|
|
3286
3568
|
}
|
|
3569
|
+
const itemsTableExists = await context.tableExists();
|
|
3570
|
+
if (!itemsTableExists) {
|
|
3571
|
+
await context.createItemsTable();
|
|
3572
|
+
}
|
|
3573
|
+
const chunksTableExists = await db2.schema.hasTable(context.getChunksTableName());
|
|
3574
|
+
if (!chunksTableExists) {
|
|
3575
|
+
await context.createChunksTable();
|
|
3576
|
+
}
|
|
3287
3577
|
const item = await db2.from(context.getTableName()).where({ id: req.params.id }).select("*").first();
|
|
3288
3578
|
if (!item) {
|
|
3289
3579
|
res.status(404).json({
|
|
@@ -3405,6 +3695,20 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3405
3695
|
}
|
|
3406
3696
|
let limit = req.query.limit ? parseInt(req.query.limit) : 10;
|
|
3407
3697
|
let page = req.query.page ? parseInt(req.query.page) : 1;
|
|
3698
|
+
let sort = req.query.sort ? req.query.sort : "created_at";
|
|
3699
|
+
let order = req.query.order ? req.query.order : "desc";
|
|
3700
|
+
if (sort && !["created_at", "embeddings_updated_at"].includes(sort)) {
|
|
3701
|
+
res.status(400).json({
|
|
3702
|
+
message: "Invalid sort field, must be one of: createdAt, embeddings_updated_at"
|
|
3703
|
+
});
|
|
3704
|
+
return;
|
|
3705
|
+
}
|
|
3706
|
+
if (order && !["desc", "asc"].includes(order)) {
|
|
3707
|
+
res.status(400).json({
|
|
3708
|
+
message: "Invalid order, must be one of: desc, asc"
|
|
3709
|
+
});
|
|
3710
|
+
return;
|
|
3711
|
+
}
|
|
3408
3712
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
3409
3713
|
if (!authenticationResult.user?.id) {
|
|
3410
3714
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
@@ -3428,6 +3732,8 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3428
3732
|
return;
|
|
3429
3733
|
}
|
|
3430
3734
|
const result = await context.getItems({
|
|
3735
|
+
sort,
|
|
3736
|
+
order,
|
|
3431
3737
|
page,
|
|
3432
3738
|
limit,
|
|
3433
3739
|
archived: req.query.archived === "true",
|
|
@@ -3507,6 +3813,18 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3507
3813
|
message: "Embedding deleted."
|
|
3508
3814
|
});
|
|
3509
3815
|
});
|
|
3816
|
+
app.get("/ping", async (req, res) => {
|
|
3817
|
+
const authenticationResult = await requestValidators.authenticate(req);
|
|
3818
|
+
if (!authenticationResult.user?.id) {
|
|
3819
|
+
res.status(200).json({
|
|
3820
|
+
authenticated: false
|
|
3821
|
+
});
|
|
3822
|
+
return;
|
|
3823
|
+
}
|
|
3824
|
+
res.status(200).json({
|
|
3825
|
+
authenticated: true
|
|
3826
|
+
});
|
|
3827
|
+
});
|
|
3510
3828
|
console.log("[EXULU] statistics timeseries");
|
|
3511
3829
|
app.post("/statistics/timeseries", async (req, res) => {
|
|
3512
3830
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
@@ -3646,6 +3964,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3646
3964
|
slug: "/contexts/" + context.id,
|
|
3647
3965
|
active: context.active,
|
|
3648
3966
|
fields: context.fields,
|
|
3967
|
+
configuration: context.configuration,
|
|
3649
3968
|
sources: context.sources.get().map((source) => ({
|
|
3650
3969
|
id: source.id,
|
|
3651
3970
|
name: source.name,
|
|
@@ -3840,47 +4159,28 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3840
4159
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
3841
4160
|
return;
|
|
3842
4161
|
}
|
|
4162
|
+
console.log("[EXULU] agent tools", agentInstance.tools);
|
|
4163
|
+
const enabledTools = agentInstance.tools.map((tool2) => tools.find(({ id }) => id === tool2)).filter(Boolean);
|
|
4164
|
+
console.log("[EXULU] enabled tools", enabledTools);
|
|
3843
4165
|
if (!!stream) {
|
|
3844
|
-
const
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
const { textStream } = await chatClient.stream(req.body.messages, {
|
|
3852
|
-
threadId: `${req.body.threadId}`,
|
|
3853
|
-
// conversation id
|
|
3854
|
-
resourceId: `${req.body.resourceId}`,
|
|
3855
|
-
// user id
|
|
3856
|
-
...agent.outputSchema && { output: agent.outputSchema },
|
|
3857
|
-
maxRetries: 2,
|
|
3858
|
-
// todo make part of ExuluAgent class
|
|
3859
|
-
maxSteps: 5,
|
|
3860
|
-
// todo make part of ExuluAgent class
|
|
3861
|
-
onError: (error) => console.error("[EXULU] chat stream error.", error),
|
|
3862
|
-
onFinish: ({ response, usage }) => console.info(
|
|
3863
|
-
"[EXULU] chat stream finished.",
|
|
3864
|
-
usage
|
|
3865
|
-
)
|
|
4166
|
+
const result = agent.generateStream({
|
|
4167
|
+
messages: req.body.messages,
|
|
4168
|
+
tools: enabledTools,
|
|
4169
|
+
statistics: {
|
|
4170
|
+
label: agent.name,
|
|
4171
|
+
trigger: "agent"
|
|
4172
|
+
}
|
|
3866
4173
|
});
|
|
3867
|
-
|
|
3868
|
-
res.write(`data: ${delta}
|
|
3869
|
-
|
|
3870
|
-
`);
|
|
3871
|
-
}
|
|
3872
|
-
res.end();
|
|
4174
|
+
result.pipeDataStreamToResponse(res);
|
|
3873
4175
|
return;
|
|
3874
4176
|
} else {
|
|
3875
|
-
const response = await agent.
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
maxSteps: 5
|
|
3883
|
-
// todo make part of ExuluAgent class
|
|
4177
|
+
const response = await agent.generateSync({
|
|
4178
|
+
messages: req.body.messages,
|
|
4179
|
+
tools: enabledTools.map(),
|
|
4180
|
+
statistics: {
|
|
4181
|
+
label: agent.name,
|
|
4182
|
+
trigger: "agent"
|
|
4183
|
+
}
|
|
3884
4184
|
});
|
|
3885
4185
|
res.status(200).json(response);
|
|
3886
4186
|
return;
|
|
@@ -3955,7 +4255,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3955
4255
|
console.log("Routes:");
|
|
3956
4256
|
console.table(routeLogs);
|
|
3957
4257
|
const TARGET_API = "https://api.anthropic.com";
|
|
3958
|
-
app.use("/gateway/anthropic", import_express3.default.raw({ type: "*/*", limit: REQUEST_SIZE_LIMIT }), async (req, res) => {
|
|
4258
|
+
app.use("/gateway/anthropic/:id", import_express3.default.raw({ type: "*/*", limit: REQUEST_SIZE_LIMIT }), async (req, res) => {
|
|
3959
4259
|
const path3 = req.url;
|
|
3960
4260
|
const url = `${TARGET_API}${path3}`;
|
|
3961
4261
|
console.log("[PROXY] Manual proxy to:", url);
|
|
@@ -3966,57 +4266,100 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3966
4266
|
console.log("[PROXY] Request stream:", req.body.stream);
|
|
3967
4267
|
console.log("[PROXY] Request messages:", req.body.messages?.length);
|
|
3968
4268
|
try {
|
|
3969
|
-
const headers = {
|
|
3970
|
-
"x-api-key": process.env.ANTHROPIC_API_KEY,
|
|
3971
|
-
"anthropic-version": "2023-06-01",
|
|
3972
|
-
"content-type": req.headers["content-type"] || "application/json"
|
|
3973
|
-
};
|
|
3974
|
-
if (req.headers["accept"]) headers["accept"] = req.headers["accept"];
|
|
3975
|
-
if (req.headers["user-agent"]) headers["user-agent"] = req.headers["user-agent"];
|
|
3976
4269
|
console.log("[PROXY] Request body tools array length:", req.body.tools?.length);
|
|
3977
4270
|
if (!req.body.tools) {
|
|
3978
4271
|
req.body.tools = [];
|
|
3979
4272
|
}
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
4273
|
+
const authenticationResult = await requestValidators.authenticate(req);
|
|
4274
|
+
if (!authenticationResult.user?.id) {
|
|
4275
|
+
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
4276
|
+
return;
|
|
4277
|
+
}
|
|
4278
|
+
console.log("[EXULU] authentication result", authenticationResult);
|
|
4279
|
+
const { db: db2 } = await postgresClient();
|
|
4280
|
+
const agent = await db2.from("agents").where({
|
|
4281
|
+
id: req.params.id
|
|
4282
|
+
}).first();
|
|
4283
|
+
if (!agent) {
|
|
4284
|
+
const arrayBuffer = createCustomAnthropicStreamingMessage(`
|
|
4285
|
+
\x1B[41m -- Agent ${req.params.id} not found or you do not have access to it. --
|
|
4286
|
+
\x1B[0m`);
|
|
4287
|
+
res.setHeader("Content-Type", "application/json");
|
|
4288
|
+
res.end(Buffer.from(arrayBuffer));
|
|
4289
|
+
return;
|
|
4290
|
+
}
|
|
4291
|
+
console.log("[EXULU] agent", agent?.name);
|
|
4292
|
+
if (!process.env.NEXTAUTH_SECRET) {
|
|
4293
|
+
const arrayBuffer = createCustomAnthropicStreamingMessage(CLAUDE_MESSAGES.missing_nextauth_secret);
|
|
4294
|
+
res.setHeader("Content-Type", "application/json");
|
|
4295
|
+
res.end(Buffer.from(arrayBuffer));
|
|
3990
4296
|
return;
|
|
3991
4297
|
}
|
|
4298
|
+
if (!authenticationResult.user?.anthropic_token) {
|
|
4299
|
+
const arrayBuffer = createCustomAnthropicStreamingMessage(CLAUDE_MESSAGES.not_enabled);
|
|
4300
|
+
res.setHeader("Content-Type", "application/json");
|
|
4301
|
+
res.end(Buffer.from(arrayBuffer));
|
|
4302
|
+
return;
|
|
4303
|
+
}
|
|
4304
|
+
const bytes = import_crypto_js2.default.AES.decrypt(authenticationResult.user?.anthropic_token, process.env.NEXTAUTH_SECRET);
|
|
4305
|
+
const anthropicApiKey = bytes.toString(import_crypto_js2.default.enc.Utf8);
|
|
4306
|
+
const headers = {
|
|
4307
|
+
"x-api-key": anthropicApiKey,
|
|
4308
|
+
"anthropic-version": "2023-06-01",
|
|
4309
|
+
"content-type": req.headers["content-type"] || "application/json"
|
|
4310
|
+
};
|
|
4311
|
+
if (req.headers["accept"]) headers["accept"] = req.headers["accept"];
|
|
4312
|
+
if (req.headers["user-agent"]) headers["user-agent"] = req.headers["user-agent"];
|
|
4313
|
+
console.log("[EXULU] anthropic api key", anthropicApiKey);
|
|
3992
4314
|
const response = await fetch(url, {
|
|
3993
4315
|
method: req.method,
|
|
3994
4316
|
headers,
|
|
3995
4317
|
body: req.method !== "GET" ? JSON.stringify(req.body) : void 0
|
|
3996
4318
|
});
|
|
3997
|
-
console.log("[PROXY] Response
|
|
4319
|
+
console.log("[PROXY] Response:", response);
|
|
4320
|
+
console.log("[PROXY] Response:", response.body);
|
|
4321
|
+
await updateStatistic({
|
|
4322
|
+
name: "count",
|
|
4323
|
+
label: "Claude Code",
|
|
4324
|
+
type: STATISTICS_TYPE_ENUM.AGENT_RUN,
|
|
4325
|
+
trigger: "claude-code",
|
|
4326
|
+
count: 1
|
|
4327
|
+
});
|
|
3998
4328
|
response.headers.forEach((value, key) => {
|
|
3999
4329
|
res.setHeader(key, value);
|
|
4000
4330
|
});
|
|
4001
4331
|
res.status(response.status);
|
|
4002
|
-
|
|
4332
|
+
const isStreaming = response.headers.get("content-type")?.includes("text/event-stream");
|
|
4333
|
+
if (isStreaming && !response?.body) {
|
|
4334
|
+
const arrayBuffer = createCustomAnthropicStreamingMessage(CLAUDE_MESSAGES.missing_body);
|
|
4335
|
+
res.setHeader("Content-Type", "application/json");
|
|
4336
|
+
res.end(Buffer.from(arrayBuffer));
|
|
4337
|
+
return;
|
|
4338
|
+
}
|
|
4339
|
+
if (isStreaming) {
|
|
4003
4340
|
const reader = response.body.getReader();
|
|
4004
4341
|
const decoder = new TextDecoder();
|
|
4005
4342
|
while (true) {
|
|
4006
4343
|
const { done, value } = await reader.read();
|
|
4007
4344
|
if (done) break;
|
|
4008
4345
|
const chunk = decoder.decode(value, { stream: true });
|
|
4346
|
+
console.log("[PROXY] Chunk:", chunk);
|
|
4009
4347
|
res.write(chunk);
|
|
4010
4348
|
}
|
|
4011
4349
|
res.end();
|
|
4012
|
-
|
|
4013
|
-
const data = await response.arrayBuffer();
|
|
4014
|
-
res.end(Buffer.from(data));
|
|
4350
|
+
return;
|
|
4015
4351
|
}
|
|
4352
|
+
const data = await response.arrayBuffer();
|
|
4353
|
+
console.log("[PROXY] Data:", data);
|
|
4354
|
+
res.end(Buffer.from(data));
|
|
4016
4355
|
} catch (error) {
|
|
4017
4356
|
console.error("[PROXY] Manual proxy error:", error);
|
|
4018
4357
|
if (!res.headersSent) {
|
|
4019
|
-
|
|
4358
|
+
if (error?.message === "Invalid token") {
|
|
4359
|
+
res.status(500).json({ error: "Authentication error, please check your IMP token and try again." });
|
|
4360
|
+
} else {
|
|
4361
|
+
res.status(500).json({ error: error.message });
|
|
4362
|
+
}
|
|
4020
4363
|
}
|
|
4021
4364
|
}
|
|
4022
4365
|
});
|
|
@@ -4064,6 +4407,20 @@ var getPresignedFileUrl = async (key) => {
|
|
|
4064
4407
|
console.log(`[EXULU] presigned url for file with key: ${key}, generated: ${json.url}`);
|
|
4065
4408
|
return json.url;
|
|
4066
4409
|
};
|
|
4410
|
+
var createCustomAnthropicStreamingMessage = (message) => {
|
|
4411
|
+
const responseData = {
|
|
4412
|
+
type: "message",
|
|
4413
|
+
content: [
|
|
4414
|
+
{
|
|
4415
|
+
type: "text",
|
|
4416
|
+
text: message
|
|
4417
|
+
}
|
|
4418
|
+
]
|
|
4419
|
+
};
|
|
4420
|
+
const jsonString = JSON.stringify(responseData);
|
|
4421
|
+
const arrayBuffer = new TextEncoder().encode(jsonString).buffer;
|
|
4422
|
+
return arrayBuffer;
|
|
4423
|
+
};
|
|
4067
4424
|
|
|
4068
4425
|
// src/registry/workers.ts
|
|
4069
4426
|
var import_ioredis = __toESM(require("ioredis"), 1);
|
|
@@ -4116,7 +4473,7 @@ var fs2 = __toESM(require("fs"), 1);
|
|
|
4116
4473
|
var import_path = __toESM(require("path"), 1);
|
|
4117
4474
|
var defaultLogsDir = import_path.default.join(process.cwd(), "logs");
|
|
4118
4475
|
var redisConnection;
|
|
4119
|
-
var createWorkers = async (queues2, contexts,
|
|
4476
|
+
var createWorkers = async (queues2, contexts, workflows, _logsDir) => {
|
|
4120
4477
|
if (!redisServer.host || !redisServer.port) {
|
|
4121
4478
|
console.error("[EXULU] you are trying to start workers, but no redis server is configured in the environment.");
|
|
4122
4479
|
throw new Error("No redis server configured in the environment, so cannot start workers.");
|
|
@@ -4147,7 +4504,7 @@ var createWorkers = async (queues2, contexts, embedders, workflows, _logsDir) =>
|
|
|
4147
4504
|
if (!bullmqJob.data.embedder) {
|
|
4148
4505
|
throw new Error(`No embedder set for embedder job.`);
|
|
4149
4506
|
}
|
|
4150
|
-
const embedder =
|
|
4507
|
+
const embedder = contexts.find((context2) => context2.embedder?.id === bullmqJob.data.embedder);
|
|
4151
4508
|
if (!embedder) {
|
|
4152
4509
|
throw new Error(`Embedder ${bullmqJob.data.embedder} not found in the registry.`);
|
|
4153
4510
|
}
|
|
@@ -4187,6 +4544,9 @@ var createWorkers = async (queues2, contexts, embedders, workflows, _logsDir) =>
|
|
|
4187
4544
|
duration,
|
|
4188
4545
|
result: JSON.stringify(result)
|
|
4189
4546
|
});
|
|
4547
|
+
await db2.from((void 0).getTableName()).where({ id: result[0].id }).update({
|
|
4548
|
+
embeddings_updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4549
|
+
}).returning("id");
|
|
4190
4550
|
return result;
|
|
4191
4551
|
}
|
|
4192
4552
|
if (bullmqJob.data.type === "workflow") {
|
|
@@ -4284,7 +4644,7 @@ var ExuluMCP = class {
|
|
|
4284
4644
|
express;
|
|
4285
4645
|
constructor() {
|
|
4286
4646
|
}
|
|
4287
|
-
create = async ({ express: express3, contexts,
|
|
4647
|
+
create = async ({ express: express3, contexts, agents, workflows, config, tools }) => {
|
|
4288
4648
|
this.express = express3;
|
|
4289
4649
|
if (!this.server) {
|
|
4290
4650
|
console.log("[EXULU] Creating MCP server.");
|
|
@@ -4415,28 +4775,210 @@ ${code}`
|
|
|
4415
4775
|
|
|
4416
4776
|
// src/registry/index.ts
|
|
4417
4777
|
var import_express7 = __toESM(require("express"), 1);
|
|
4778
|
+
|
|
4779
|
+
// src/templates/agents/claude-code.ts
|
|
4780
|
+
var agentId = "0832-5178-1145-2194";
|
|
4781
|
+
var claudeCodeAgent = new ExuluAgent({
|
|
4782
|
+
id: `${agentId}-claude-code-agent`,
|
|
4783
|
+
name: `Claude Code Agent`,
|
|
4784
|
+
description: `Claude Code agent, enabling the creation of multiple Claude Code Agent instances with different configurations (rate limits, functions, etc).`,
|
|
4785
|
+
type: "custom"
|
|
4786
|
+
});
|
|
4787
|
+
|
|
4788
|
+
// src/templates/agents/claude-opus-4.ts
|
|
4789
|
+
var import_anthropic = require("@ai-sdk/anthropic");
|
|
4790
|
+
var import_zod4 = require("zod");
|
|
4791
|
+
var agentId2 = "5434-5678-9143-2590";
|
|
4792
|
+
var defaultAgent = new ExuluAgent({
|
|
4793
|
+
id: `${agentId2}-default-claude-4-opus-agent`,
|
|
4794
|
+
name: `Default Claude 4 Opus Agent`,
|
|
4795
|
+
description: `Basic agent without any defined tools, that can support MCP's.`,
|
|
4796
|
+
type: "agent",
|
|
4797
|
+
capabilities: {
|
|
4798
|
+
tools: false,
|
|
4799
|
+
images: [],
|
|
4800
|
+
files: [],
|
|
4801
|
+
audio: [],
|
|
4802
|
+
video: []
|
|
4803
|
+
},
|
|
4804
|
+
evals: [],
|
|
4805
|
+
config: {
|
|
4806
|
+
name: `Default agent`,
|
|
4807
|
+
instructions: "You are a helpful assistant.",
|
|
4808
|
+
model: (0, import_anthropic.anthropic)("claude-4-opus-20250514"),
|
|
4809
|
+
// todo add a field of type string that adds a dropdown list from which the user can select the model
|
|
4810
|
+
// todo for each model, check which provider is used, and require the admin to add one or multiple
|
|
4811
|
+
// API keys for the provider (which we can then auto-rotate).
|
|
4812
|
+
// todo also add custom fields for rate limiting, so the admin can set custom rate limits for the agent
|
|
4813
|
+
// and allow him/her to decide if the rate limit is per user or per agent.
|
|
4814
|
+
// todo finally allow switching on or off immutable audit logs on the agent. Which then enables OTEL
|
|
4815
|
+
// and stores the logs into the pre-defined storage.
|
|
4816
|
+
custom: import_zod4.z.object({
|
|
4817
|
+
apiKey: import_zod4.z.string()
|
|
4818
|
+
})
|
|
4819
|
+
}
|
|
4820
|
+
});
|
|
4821
|
+
|
|
4822
|
+
// src/templates/tools/browserbase.ts
|
|
4823
|
+
var import_zod5 = require("zod");
|
|
4824
|
+
var import_stagehand = require("@browserbasehq/stagehand");
|
|
4825
|
+
var import_sdk = require("@browserbasehq/sdk");
|
|
4826
|
+
var PROJECT_ID = "811444dd-6e6d-40b5-bd90-541c93e44be6";
|
|
4827
|
+
process.env.BROWSERBASE_PROJECT_ID = PROJECT_ID;
|
|
4828
|
+
var BB_API_KEY = "bb_live_LwMwNgZB5cIEKcBwMuAugrgNkFM";
|
|
4829
|
+
async function createContext() {
|
|
4830
|
+
const bb = new import_sdk.Browserbase({ apiKey: BB_API_KEY });
|
|
4831
|
+
const context = await bb.contexts.create({
|
|
4832
|
+
projectId: PROJECT_ID
|
|
4833
|
+
});
|
|
4834
|
+
return context;
|
|
4835
|
+
}
|
|
4836
|
+
async function createAuthSession(contextId) {
|
|
4837
|
+
const bb = new import_sdk.Browserbase({ apiKey: BB_API_KEY });
|
|
4838
|
+
const session = await bb.sessions.create({
|
|
4839
|
+
projectId: PROJECT_ID,
|
|
4840
|
+
browserSettings: {
|
|
4841
|
+
context: {
|
|
4842
|
+
id: contextId,
|
|
4843
|
+
persist: true
|
|
4844
|
+
}
|
|
4845
|
+
}
|
|
4846
|
+
/* proxies: [{ // not included in the free tier
|
|
4847
|
+
type: "browserbase",
|
|
4848
|
+
geolocation: {
|
|
4849
|
+
city: CITY,
|
|
4850
|
+
country: COUNTRY
|
|
4851
|
+
}
|
|
4852
|
+
}] */
|
|
4853
|
+
});
|
|
4854
|
+
const liveViewLinks = await bb.sessions.debug(session.id);
|
|
4855
|
+
const liveViewLink = liveViewLinks.debuggerFullscreenUrl;
|
|
4856
|
+
console.log(`\u{1F50D} Live View Link: ${liveViewLink}`);
|
|
4857
|
+
console.log("Session URL: https://browserbase.com/sessions/" + session.id);
|
|
4858
|
+
return {
|
|
4859
|
+
url: liveViewLink,
|
|
4860
|
+
id: session.id
|
|
4861
|
+
};
|
|
4862
|
+
}
|
|
4863
|
+
var createSession = new ExuluTool({
|
|
4864
|
+
id: `1234-5178-9423-4267`,
|
|
4865
|
+
type: "function",
|
|
4866
|
+
name: "Create a browserbase session.",
|
|
4867
|
+
description: `
|
|
4868
|
+
Creates a browserbase session and returns the live view url as well as
|
|
4869
|
+
the session id as a JSON object. A browserbase session is a headless browser
|
|
4870
|
+
that can be used to to visit websites and perform actions.
|
|
4871
|
+
`,
|
|
4872
|
+
execute: async () => {
|
|
4873
|
+
const { id } = await createContext();
|
|
4874
|
+
return await createAuthSession(id);
|
|
4875
|
+
}
|
|
4876
|
+
});
|
|
4877
|
+
var askChatgpt = new ExuluTool({
|
|
4878
|
+
id: `1234-5178-9423-4268`,
|
|
4879
|
+
type: "function",
|
|
4880
|
+
name: "ChatGPT browserbase operation.",
|
|
4881
|
+
inputSchema: import_zod5.z.object({
|
|
4882
|
+
session: import_zod5.z.string().describe("The session id of the browserbase session."),
|
|
4883
|
+
question: import_zod5.z.string().describe("The question to ask ChatGPT.")
|
|
4884
|
+
}),
|
|
4885
|
+
description: `Uses an existing, authenticated browserbase session to visit ChatGPT and perform actions such as asking questions.`,
|
|
4886
|
+
execute: async ({ session, question }) => {
|
|
4887
|
+
const stagehand = new import_stagehand.Stagehand({
|
|
4888
|
+
// With npx create-browser-app, this config is found
|
|
4889
|
+
// in a separate stagehand.config.ts file
|
|
4890
|
+
env: "BROWSERBASE",
|
|
4891
|
+
// set to "LOCAL" for local development
|
|
4892
|
+
apiKey: BB_API_KEY,
|
|
4893
|
+
// todo make this a config variable the admin can set in the UI
|
|
4894
|
+
modelName: "openai/gpt-4.1-mini",
|
|
4895
|
+
// todo change to claude || optionally make configurable?
|
|
4896
|
+
browserbaseSessionID: session,
|
|
4897
|
+
modelClientOptions: {
|
|
4898
|
+
apiKey: process.env.OPENAI_API_KEY
|
|
4899
|
+
// todo make this a config variable the admin can set in the UI
|
|
4900
|
+
}
|
|
4901
|
+
});
|
|
4902
|
+
await stagehand.init();
|
|
4903
|
+
const page = stagehand.page;
|
|
4904
|
+
await page.goto("https://chatgpt.com");
|
|
4905
|
+
await page.act(`Type in '${question}' into the search bar`);
|
|
4906
|
+
const { answer } = await page.extract({
|
|
4907
|
+
instruction: "The answer to the question generated by ChatGPT.",
|
|
4908
|
+
schema: import_zod5.z.object({
|
|
4909
|
+
answer: import_zod5.z.string()
|
|
4910
|
+
})
|
|
4911
|
+
});
|
|
4912
|
+
console.log(answer);
|
|
4913
|
+
await stagehand.close();
|
|
4914
|
+
return {
|
|
4915
|
+
answer
|
|
4916
|
+
};
|
|
4917
|
+
}
|
|
4918
|
+
});
|
|
4919
|
+
|
|
4920
|
+
// src/templates/tools/jira.ts
|
|
4921
|
+
var import_zod6 = require("zod");
|
|
4922
|
+
var getTicket = new ExuluTool({
|
|
4923
|
+
id: `1414-5179-1423-1269`,
|
|
4924
|
+
name: "JIRA ticket retrieval.",
|
|
4925
|
+
type: "function",
|
|
4926
|
+
inputSchema: import_zod6.z.object({
|
|
4927
|
+
ticketId: import_zod6.z.string().describe("The id of the ticket to retrieve.")
|
|
4928
|
+
}),
|
|
4929
|
+
description: `Retrieves a ticket from Jira.`,
|
|
4930
|
+
execute: async ({ session, question }) => {
|
|
4931
|
+
return {
|
|
4932
|
+
name: "BYD-1234",
|
|
4933
|
+
id: "12345678",
|
|
4934
|
+
status: "Open",
|
|
4935
|
+
description: "This is a test ticket",
|
|
4936
|
+
assignee: "John Doe",
|
|
4937
|
+
createdAt: "2021-01-01",
|
|
4938
|
+
updatedAt: "2021-01-01",
|
|
4939
|
+
dueDate: "2021-01-01",
|
|
4940
|
+
priority: "High"
|
|
4941
|
+
};
|
|
4942
|
+
}
|
|
4943
|
+
});
|
|
4944
|
+
|
|
4945
|
+
// src/registry/index.ts
|
|
4418
4946
|
var ExuluApp = class {
|
|
4419
4947
|
_agents = [];
|
|
4420
4948
|
_workflows = [];
|
|
4421
4949
|
_config;
|
|
4422
|
-
_embedders = [];
|
|
4423
4950
|
_queues = [];
|
|
4424
4951
|
_contexts = {};
|
|
4425
4952
|
_tools = [];
|
|
4426
4953
|
_expressApp = null;
|
|
4427
4954
|
constructor() {
|
|
4428
4955
|
}
|
|
4429
|
-
// Factory function so we can async
|
|
4430
|
-
// MCP server if needed.
|
|
4431
|
-
create = async ({ contexts,
|
|
4432
|
-
this._embedders = embedders ?? [];
|
|
4956
|
+
// Factory function so we can async
|
|
4957
|
+
// initialize the MCP server if needed.
|
|
4958
|
+
create = async ({ contexts, agents, workflows, config, tools }) => {
|
|
4433
4959
|
this._workflows = workflows ?? [];
|
|
4434
4960
|
this._contexts = contexts ?? {};
|
|
4435
|
-
this._agents =
|
|
4961
|
+
this._agents = [
|
|
4962
|
+
claudeCodeAgent,
|
|
4963
|
+
defaultAgent,
|
|
4964
|
+
...agents ?? []
|
|
4965
|
+
];
|
|
4436
4966
|
this._config = config;
|
|
4437
|
-
this._tools =
|
|
4967
|
+
this._tools = [
|
|
4968
|
+
...tools ?? [],
|
|
4969
|
+
// Add contexts as tools
|
|
4970
|
+
...Object.values(contexts || {}).map((context) => context.tool()),
|
|
4971
|
+
// Add agents as tools
|
|
4972
|
+
...(agents || []).map((agent) => agent.tool()),
|
|
4973
|
+
...[
|
|
4974
|
+
createSession,
|
|
4975
|
+
askChatgpt,
|
|
4976
|
+
getTicket
|
|
4977
|
+
]
|
|
4978
|
+
];
|
|
4979
|
+
const contextsArray = Object.values(contexts || {});
|
|
4438
4980
|
const queues2 = [
|
|
4439
|
-
...
|
|
4981
|
+
...contextsArray?.length ? contextsArray.map((context) => context.embedder.queue?.name || null) : [],
|
|
4440
4982
|
...workflows?.length ? workflows.map((workflow) => workflow.queue?.name || null) : []
|
|
4441
4983
|
];
|
|
4442
4984
|
this._queues = [...new Set(queues2.filter((o) => !!o))];
|
|
@@ -4453,9 +4995,6 @@ var ExuluApp = class {
|
|
|
4453
4995
|
}
|
|
4454
4996
|
return this._expressApp;
|
|
4455
4997
|
}
|
|
4456
|
-
embedder(id) {
|
|
4457
|
-
return this._embedders.find((x) => x.id === id);
|
|
4458
|
-
}
|
|
4459
4998
|
tool(id) {
|
|
4460
4999
|
return this._tools.find((x) => x.id === id);
|
|
4461
5000
|
}
|
|
@@ -4471,9 +5010,6 @@ var ExuluApp = class {
|
|
|
4471
5010
|
workflow(id) {
|
|
4472
5011
|
return this._workflows.find((x) => x.id === id);
|
|
4473
5012
|
}
|
|
4474
|
-
get embedders() {
|
|
4475
|
-
return this._embedders;
|
|
4476
|
-
}
|
|
4477
5013
|
get contexts() {
|
|
4478
5014
|
return Object.values(this._contexts ?? {});
|
|
4479
5015
|
}
|
|
@@ -4489,7 +5025,6 @@ var ExuluApp = class {
|
|
|
4489
5025
|
return await createWorkers(
|
|
4490
5026
|
this._queues,
|
|
4491
5027
|
Object.values(this._contexts ?? {}),
|
|
4492
|
-
this._embedders,
|
|
4493
5028
|
this._workflows,
|
|
4494
5029
|
this._config?.workers?.logsDir
|
|
4495
5030
|
);
|
|
@@ -4506,7 +5041,6 @@ var ExuluApp = class {
|
|
|
4506
5041
|
await createExpressRoutes(
|
|
4507
5042
|
app,
|
|
4508
5043
|
this._agents,
|
|
4509
|
-
this._embedders,
|
|
4510
5044
|
this._tools,
|
|
4511
5045
|
this._workflows,
|
|
4512
5046
|
Object.values(this._contexts ?? {})
|
|
@@ -4516,7 +5050,6 @@ var ExuluApp = class {
|
|
|
4516
5050
|
await mcp.create({
|
|
4517
5051
|
express: app,
|
|
4518
5052
|
contexts: this._contexts,
|
|
4519
|
-
embedders: this._embedders,
|
|
4520
5053
|
agents: this._agents,
|
|
4521
5054
|
workflows: this._workflows,
|
|
4522
5055
|
config: this._config,
|
|
@@ -5724,198 +6257,6 @@ var SentenceChunker = class _SentenceChunker extends BaseChunker {
|
|
|
5724
6257
|
}
|
|
5725
6258
|
};
|
|
5726
6259
|
|
|
5727
|
-
// src/cli/index.tsx
|
|
5728
|
-
var import_react2 = require("react");
|
|
5729
|
-
var import_ink4 = require("ink");
|
|
5730
|
-
var import_ui5 = require("@inkjs/ui");
|
|
5731
|
-
var import_patch_console = __toESM(require("patch-console"), 1);
|
|
5732
|
-
|
|
5733
|
-
// src/cli/components/nav.tsx
|
|
5734
|
-
var import_ui = require("@inkjs/ui");
|
|
5735
|
-
var import_ink = require("ink");
|
|
5736
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
5737
|
-
var nav = [
|
|
5738
|
-
{
|
|
5739
|
-
label: "Agents",
|
|
5740
|
-
value: "agents"
|
|
5741
|
-
},
|
|
5742
|
-
{
|
|
5743
|
-
label: "Start Claude Code",
|
|
5744
|
-
value: "claude-code"
|
|
5745
|
-
},
|
|
5746
|
-
{
|
|
5747
|
-
label: "Exit",
|
|
5748
|
-
value: "exit"
|
|
5749
|
-
}
|
|
5750
|
-
];
|
|
5751
|
-
var Nav = ({ setView }) => {
|
|
5752
|
-
const { exit } = (0, import_ink.useApp)();
|
|
5753
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ui.Select, { options: nav, onChange: (value) => {
|
|
5754
|
-
if (value === "exit") {
|
|
5755
|
-
exit();
|
|
5756
|
-
}
|
|
5757
|
-
setView(value);
|
|
5758
|
-
} });
|
|
5759
|
-
};
|
|
5760
|
-
var nav_default = Nav;
|
|
5761
|
-
|
|
5762
|
-
// src/cli/components/agent-selector.tsx
|
|
5763
|
-
var import_ink2 = require("ink");
|
|
5764
|
-
var import_ui2 = require("@inkjs/ui");
|
|
5765
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
5766
|
-
var AgentSelector = ({ exulu, setAgent, setEvaluations }) => {
|
|
5767
|
-
const agents = exulu.agents.map((agent) => ({
|
|
5768
|
-
label: agent.name,
|
|
5769
|
-
value: agent.id
|
|
5770
|
-
}));
|
|
5771
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
5772
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { children: "Please select an agent:" }),
|
|
5773
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui2.Select, { options: agents, onChange: (value) => {
|
|
5774
|
-
const agent = exulu.agent(value);
|
|
5775
|
-
if (!agent) {
|
|
5776
|
-
console.error("Agent not found", value);
|
|
5777
|
-
return;
|
|
5778
|
-
}
|
|
5779
|
-
setAgent(agent);
|
|
5780
|
-
if (agent) {
|
|
5781
|
-
setEvaluations(agent.evals || []);
|
|
5782
|
-
}
|
|
5783
|
-
} })
|
|
5784
|
-
] });
|
|
5785
|
-
};
|
|
5786
|
-
var agent_selector_default = AgentSelector;
|
|
5787
|
-
|
|
5788
|
-
// src/cli/components/eval-selector.tsx
|
|
5789
|
-
var import_ui3 = require("@inkjs/ui");
|
|
5790
|
-
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
5791
|
-
var EvalSelector = ({ evaluations, setEvaluation }) => {
|
|
5792
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui3.Select, { options: evaluations.map((evaluation) => ({
|
|
5793
|
-
label: evaluation.runner.name,
|
|
5794
|
-
value: evaluation.runner.name
|
|
5795
|
-
})), onChange: (value) => {
|
|
5796
|
-
const evaluation = evaluations?.find((evaluation2) => evaluation2.runner.name === value);
|
|
5797
|
-
if (evaluation) {
|
|
5798
|
-
setEvaluation(evaluation);
|
|
5799
|
-
}
|
|
5800
|
-
} });
|
|
5801
|
-
};
|
|
5802
|
-
var eval_selector_default = EvalSelector;
|
|
5803
|
-
|
|
5804
|
-
// src/cli/components/eval-actions.tsx
|
|
5805
|
-
var import_react = require("react");
|
|
5806
|
-
var import_ui4 = require("@inkjs/ui");
|
|
5807
|
-
var import_ink3 = require("ink");
|
|
5808
|
-
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
5809
|
-
var EvalActions = ({ agent, evaluation, setEvaluation }) => {
|
|
5810
|
-
const [progress, setProgress] = (0, import_react.useState)(0);
|
|
5811
|
-
const [results, setResults] = (0, import_react.useState)([]);
|
|
5812
|
-
const [running, setRunning] = (0, import_react.useState)();
|
|
5813
|
-
const run = async (evaluation2) => {
|
|
5814
|
-
setRunning({
|
|
5815
|
-
label: evaluation2.runner.name
|
|
5816
|
-
});
|
|
5817
|
-
const testCases = evaluation2.runner.testcases;
|
|
5818
|
-
const total = testCases.length;
|
|
5819
|
-
if (!testCases) {
|
|
5820
|
-
throw new Error("No test cases found");
|
|
5821
|
-
}
|
|
5822
|
-
let i = 0;
|
|
5823
|
-
for (const testCase of testCases) {
|
|
5824
|
-
i++;
|
|
5825
|
-
const result = await evaluation2.runner.run({
|
|
5826
|
-
data: testCase,
|
|
5827
|
-
runner: {
|
|
5828
|
-
agent
|
|
5829
|
-
}
|
|
5830
|
-
});
|
|
5831
|
-
setProgress(Math.round(i / total * 100));
|
|
5832
|
-
setResults([...results, {
|
|
5833
|
-
name: evaluation2.runner.name,
|
|
5834
|
-
prompt: testCase.prompt?.slice(0, 100) + "...",
|
|
5835
|
-
score: result.score,
|
|
5836
|
-
comment: result.comment
|
|
5837
|
-
}]);
|
|
5838
|
-
}
|
|
5839
|
-
setRunning(void 0);
|
|
5840
|
-
};
|
|
5841
|
-
if (progress === 100) {
|
|
5842
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
5843
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink3.Text, { children: "Evaluations completed." }),
|
|
5844
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui4.UnorderedList, { children: results.map((result) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui4.UnorderedList.Item, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink3.Text, { children: [
|
|
5845
|
-
result.name,
|
|
5846
|
-
": ",
|
|
5847
|
-
result.score,
|
|
5848
|
-
" - ",
|
|
5849
|
-
result.comment
|
|
5850
|
-
] }) })) })
|
|
5851
|
-
] });
|
|
5852
|
-
}
|
|
5853
|
-
if (running) {
|
|
5854
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
5855
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink3.Text, { children: [
|
|
5856
|
-
"Running ",
|
|
5857
|
-
running.label,
|
|
5858
|
-
"..."
|
|
5859
|
-
] }),
|
|
5860
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui4.ProgressBar, { value: progress })
|
|
5861
|
-
] });
|
|
5862
|
-
}
|
|
5863
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui4.Select, { options: [{
|
|
5864
|
-
label: "Run evaluation",
|
|
5865
|
-
value: "run"
|
|
5866
|
-
}, {
|
|
5867
|
-
label: "Go back",
|
|
5868
|
-
value: "back"
|
|
5869
|
-
}], onChange: (value) => {
|
|
5870
|
-
if (value === "back") {
|
|
5871
|
-
setEvaluation(void 0);
|
|
5872
|
-
}
|
|
5873
|
-
if (value === "run") {
|
|
5874
|
-
run(evaluation);
|
|
5875
|
-
}
|
|
5876
|
-
} });
|
|
5877
|
-
};
|
|
5878
|
-
var eval_actions_default = EvalActions;
|
|
5879
|
-
|
|
5880
|
-
// src/cli/index.tsx
|
|
5881
|
-
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
5882
|
-
var Main = ({ exulu }) => {
|
|
5883
|
-
(0, import_patch_console.default)((stream, data) => {
|
|
5884
|
-
setLogs([...logs, data]);
|
|
5885
|
-
});
|
|
5886
|
-
const [logs, setLogs] = (0, import_react2.useState)([]);
|
|
5887
|
-
const [view, setView] = (0, import_react2.useState)();
|
|
5888
|
-
const [agent, setAgent] = (0, import_react2.useState)();
|
|
5889
|
-
const [evaluations, setEvaluations] = (0, import_react2.useState)([]);
|
|
5890
|
-
const [evaluation, setEvaluation] = (0, import_react2.useState)();
|
|
5891
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink4.Box, { borderStyle: "round", borderColor: "cyan", padding: 1, flexDirection: "column", width: "70%", children: [
|
|
5892
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink4.Text, { children: "Logs:" }),
|
|
5893
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ui5.UnorderedList, { children: logs.map((log, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ui5.UnorderedList.Item, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink4.Text, { children: log }) })) }),
|
|
5894
|
-
!view && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(nav_default, { setView }),
|
|
5895
|
-
view === "agents" && !agent && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(agent_selector_default, { exulu, setAgent, setEvaluations }),
|
|
5896
|
-
view === "agents" && agent && !evaluation && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
5897
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink4.Text, { children: [
|
|
5898
|
-
'Selected agent "',
|
|
5899
|
-
agent.name,
|
|
5900
|
-
'". Please select an evaluation:'
|
|
5901
|
-
] }),
|
|
5902
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(eval_selector_default, { evaluations, setEvaluation })
|
|
5903
|
-
] }),
|
|
5904
|
-
view === "agents" && agent && evaluation && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
5905
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink4.Text, { children: [
|
|
5906
|
-
"Selected evaluation: ",
|
|
5907
|
-
evaluation.runner.name
|
|
5908
|
-
] }),
|
|
5909
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(eval_actions_default, { agent, evaluation, setEvaluation })
|
|
5910
|
-
] })
|
|
5911
|
-
] });
|
|
5912
|
-
};
|
|
5913
|
-
var cli_default = {
|
|
5914
|
-
run: (exulu) => {
|
|
5915
|
-
(0, import_ink4.render)(/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Main, { exulu }));
|
|
5916
|
-
}
|
|
5917
|
-
};
|
|
5918
|
-
|
|
5919
6260
|
// src/index.ts
|
|
5920
6261
|
var ExuluJobs = {
|
|
5921
6262
|
redis: redisClient,
|
|
@@ -5946,7 +6287,6 @@ var ExuluDatabase = {
|
|
|
5946
6287
|
ExuluApp,
|
|
5947
6288
|
ExuluAuthentication,
|
|
5948
6289
|
ExuluChunkers,
|
|
5949
|
-
ExuluCli,
|
|
5950
6290
|
ExuluContext,
|
|
5951
6291
|
ExuluDatabase,
|
|
5952
6292
|
ExuluEmbedder,
|