@exulu/backend 0.1.8 → 0.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/dist/index.cjs +81 -37
- package/dist/index.js +81 -37
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -58,19 +58,26 @@ var redisServer = {
|
|
|
58
58
|
// src/redis/client.ts
|
|
59
59
|
var client = {};
|
|
60
60
|
async function redisClient() {
|
|
61
|
-
|
|
61
|
+
console.log("[EXULU] redisClient", redisServer);
|
|
62
|
+
if (!redisServer.host?.length || !redisServer.port?.length) {
|
|
63
|
+
console.error(`[EXULU] no redis server configured.`);
|
|
62
64
|
return {
|
|
63
65
|
client: null
|
|
64
66
|
};
|
|
65
67
|
}
|
|
66
68
|
if (!client["exulu"]) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
try {
|
|
70
|
+
const url = `redis://${redisServer.host}:${redisServer.port}`;
|
|
71
|
+
console.log(`[EXULU] connecting to redis.`);
|
|
72
|
+
client["exulu"] = (0, import_redis.createClient)({
|
|
73
|
+
// todo add password
|
|
74
|
+
url
|
|
75
|
+
});
|
|
76
|
+
await client["exulu"].connect();
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error(`[EXULU] error connecting to redis.`, error);
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
74
81
|
}
|
|
75
82
|
return {
|
|
76
83
|
client: client["exulu"]
|
|
@@ -113,25 +120,30 @@ var import_knex3 = require("pgvector/knex");
|
|
|
113
120
|
var db = {};
|
|
114
121
|
async function postgresClient() {
|
|
115
122
|
if (!db["exulu"]) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
123
|
+
try {
|
|
124
|
+
console.log("[EXULU] Initializing exulu database.");
|
|
125
|
+
console.log(process.env.POSTGRES_DB_HOST);
|
|
126
|
+
console.log(process.env.POSTGRES_DB_PORT);
|
|
127
|
+
console.log(process.env.POSTGRES_DB_USER);
|
|
128
|
+
console.log(process.env.POSTGRES_DB_PASSWORD);
|
|
129
|
+
console.log(process.env.POSTGRES_DB_SSL);
|
|
130
|
+
const knex = (0, import_knex.default)({
|
|
131
|
+
client: "pg",
|
|
132
|
+
connection: {
|
|
133
|
+
host: process.env.POSTGRES_DB_HOST,
|
|
134
|
+
port: parseInt(process.env.POSTGRES_DB_PORT || "5432"),
|
|
135
|
+
user: process.env.POSTGRES_DB_USER,
|
|
136
|
+
database: "exulu",
|
|
137
|
+
password: process.env.POSTGRES_DB_PASSWORD,
|
|
138
|
+
ssl: process.env.POSTGRES_DB_SSL === "true" ? { rejectUnauthorized: false } : false
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
await knex.schema.createExtensionIfNotExists("vector");
|
|
142
|
+
db["exulu"] = knex;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error("[EXULU] Error initializing exulu database.", error);
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
135
147
|
}
|
|
136
148
|
return {
|
|
137
149
|
db: db["exulu"]
|
|
@@ -398,6 +410,7 @@ var sanitizeName = (name) => {
|
|
|
398
410
|
};
|
|
399
411
|
|
|
400
412
|
// src/postgres/init-db.ts
|
|
413
|
+
var import_bcryptjs = __toESM(require("bcryptjs"), 1);
|
|
401
414
|
var up = async function(knex) {
|
|
402
415
|
if (!await knex.schema.hasTable("roles")) {
|
|
403
416
|
await knex.schema.createTable("roles", (table) => {
|
|
@@ -545,6 +558,11 @@ var up = async function(knex) {
|
|
|
545
558
|
});
|
|
546
559
|
}
|
|
547
560
|
};
|
|
561
|
+
var SALT_ROUNDS = 12;
|
|
562
|
+
async function encryptApiKey(apikey) {
|
|
563
|
+
const hash = await import_bcryptjs.default.hash(apikey, SALT_ROUNDS);
|
|
564
|
+
return hash;
|
|
565
|
+
}
|
|
548
566
|
var execute = async () => {
|
|
549
567
|
console.log("[EXULU] Initializing database.");
|
|
550
568
|
const { db: db2 } = await postgresClient();
|
|
@@ -563,6 +581,10 @@ var execute = async () => {
|
|
|
563
581
|
} else {
|
|
564
582
|
roleId = existingRole.id;
|
|
565
583
|
}
|
|
584
|
+
const newKeyName = "exulu_default_key";
|
|
585
|
+
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
586
|
+
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
587
|
+
const encryptedKey = await encryptApiKey(plainKey);
|
|
566
588
|
const existingUser = await db2.from("users").where({ email: "admin@exulu.com" }).first();
|
|
567
589
|
if (!existingUser) {
|
|
568
590
|
console.log("[EXULU] Creating default admin user.");
|
|
@@ -572,11 +594,28 @@ var execute = async () => {
|
|
|
572
594
|
super_admin: true,
|
|
573
595
|
createdAt: /* @__PURE__ */ new Date(),
|
|
574
596
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
597
|
+
type: "user",
|
|
598
|
+
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
599
|
+
role: roleId
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
const existingApiUser = await db2.from("users").where({ email: "api@exulu.com" }).first();
|
|
603
|
+
if (!existingApiUser) {
|
|
604
|
+
console.log("[EXULU] Creating default api user.");
|
|
605
|
+
await db2.from("users").insert({
|
|
606
|
+
name: "exulu",
|
|
607
|
+
email: "admin@exulu.com",
|
|
608
|
+
super_admin: true,
|
|
609
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
610
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
611
|
+
type: "api",
|
|
612
|
+
apikey: `${encryptedKey}${postFix}`,
|
|
575
613
|
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
576
614
|
role: roleId
|
|
577
615
|
});
|
|
578
616
|
}
|
|
579
617
|
console.log("[EXULU] Database initialized.");
|
|
618
|
+
console.log("[EXULU] Default api key: ", `${encryptedKey}${postFix}`);
|
|
580
619
|
return;
|
|
581
620
|
};
|
|
582
621
|
|
|
@@ -1428,7 +1467,7 @@ var import_express = require("express");
|
|
|
1428
1467
|
var import_jwt = require("next-auth/jwt");
|
|
1429
1468
|
|
|
1430
1469
|
// src/auth/auth.ts
|
|
1431
|
-
var
|
|
1470
|
+
var import_bcryptjs2 = __toESM(require("bcryptjs"), 1);
|
|
1432
1471
|
var authentication = async ({
|
|
1433
1472
|
apikey,
|
|
1434
1473
|
authtoken,
|
|
@@ -1519,11 +1558,11 @@ var authentication = async ({
|
|
|
1519
1558
|
code: 401
|
|
1520
1559
|
};
|
|
1521
1560
|
}
|
|
1522
|
-
const filtered = users.filter(({
|
|
1561
|
+
const filtered = users.filter(({ apikey: apikey2, id }) => apikey2.includes(keyName));
|
|
1523
1562
|
for (const user of filtered) {
|
|
1524
|
-
const lastSlashIndex = user.
|
|
1525
|
-
const compareValue = lastSlashIndex !== -1 ? user.
|
|
1526
|
-
const isMatch = await
|
|
1563
|
+
const lastSlashIndex = user.apikey.lastIndexOf("/");
|
|
1564
|
+
const compareValue = lastSlashIndex !== -1 ? user.apikey.substring(0, lastSlashIndex) : user.apikey;
|
|
1565
|
+
const isMatch = await import_bcryptjs2.default.compare(keyValue, compareValue);
|
|
1527
1566
|
if (isMatch) {
|
|
1528
1567
|
await db2.from("users").where({ id: user.id }).update({
|
|
1529
1568
|
lastUsed: /* @__PURE__ */ new Date()
|
|
@@ -1714,6 +1753,10 @@ var ExuluQueues = class {
|
|
|
1714
1753
|
if (existing) {
|
|
1715
1754
|
return existing;
|
|
1716
1755
|
}
|
|
1756
|
+
if (!redisServer.host?.length || !redisServer.port?.length) {
|
|
1757
|
+
console.error(`[EXULU] no redis server configured, but you are trying to use a queue ( ${name}), likely in an agent or workflow (look for ExuluQueues.use() ).`);
|
|
1758
|
+
throw new Error(`[EXULU] no redis server configured.`);
|
|
1759
|
+
}
|
|
1717
1760
|
const newQueue = new import_bullmq5.Queue(`${name}`, { connection: redisServer });
|
|
1718
1761
|
this.queues.push(newQueue);
|
|
1719
1762
|
return newQueue;
|
|
@@ -2133,9 +2176,6 @@ var createUppyRoutes = async (app) => {
|
|
|
2133
2176
|
return stsClient;
|
|
2134
2177
|
}
|
|
2135
2178
|
app.use(bodyParser.urlencoded({ extended: true }), bodyParser.json());
|
|
2136
|
-
app.get("/", (req, res) => {
|
|
2137
|
-
res.json("Exulu upload server.");
|
|
2138
|
-
});
|
|
2139
2179
|
app.get("/s3/list", async (req, res, next) => {
|
|
2140
2180
|
const apikey = req.headers["exulu-api-key"] || null;
|
|
2141
2181
|
let authtoken = null;
|
|
@@ -2562,7 +2602,11 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2562
2602
|
{ route: "/items/export/:context", method: "GET", note: "Export items from context" },
|
|
2563
2603
|
{ route: "/graphql", method: "POST", note: "GraphQL endpoint" }
|
|
2564
2604
|
);
|
|
2565
|
-
|
|
2605
|
+
if (redisServer.host?.length && redisServer.port?.length) {
|
|
2606
|
+
await createRecurringJobs();
|
|
2607
|
+
} else {
|
|
2608
|
+
console.log("===========================", "[EXULU] no redis server configured, not setting up recurring jobs.", "===========================");
|
|
2609
|
+
}
|
|
2566
2610
|
const schema = createSDL([usersSchema, rolesSchema, agentsSchema, jobsSchema]);
|
|
2567
2611
|
const server = new import_server3.ApolloServer({ schema, introspection: true });
|
|
2568
2612
|
await server.start();
|
|
@@ -2622,7 +2666,6 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2622
2666
|
}
|
|
2623
2667
|
});
|
|
2624
2668
|
});
|
|
2625
|
-
console.log("tools", tools);
|
|
2626
2669
|
app.get("/tools", async (req, res) => {
|
|
2627
2670
|
res.status(200).json(tools.map((tool) => ({
|
|
2628
2671
|
id: tool.id,
|
|
@@ -3283,6 +3326,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3283
3326
|
return;
|
|
3284
3327
|
}
|
|
3285
3328
|
if (agent.rateLimit) {
|
|
3329
|
+
console.log("[EXULU] rate limiting agent.", agent.rateLimit);
|
|
3286
3330
|
const limit = await rateLimiter(
|
|
3287
3331
|
agent.rateLimit.name || agent.id,
|
|
3288
3332
|
agent.rateLimit.rate_limit.time,
|
package/dist/index.js
CHANGED
|
@@ -17,19 +17,26 @@ var redisServer = {
|
|
|
17
17
|
// src/redis/client.ts
|
|
18
18
|
var client = {};
|
|
19
19
|
async function redisClient() {
|
|
20
|
-
|
|
20
|
+
console.log("[EXULU] redisClient", redisServer);
|
|
21
|
+
if (!redisServer.host?.length || !redisServer.port?.length) {
|
|
22
|
+
console.error(`[EXULU] no redis server configured.`);
|
|
21
23
|
return {
|
|
22
24
|
client: null
|
|
23
25
|
};
|
|
24
26
|
}
|
|
25
27
|
if (!client["exulu"]) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
try {
|
|
29
|
+
const url = `redis://${redisServer.host}:${redisServer.port}`;
|
|
30
|
+
console.log(`[EXULU] connecting to redis.`);
|
|
31
|
+
client["exulu"] = createClient({
|
|
32
|
+
// todo add password
|
|
33
|
+
url
|
|
34
|
+
});
|
|
35
|
+
await client["exulu"].connect();
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error(`[EXULU] error connecting to redis.`, error);
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
33
40
|
}
|
|
34
41
|
return {
|
|
35
42
|
client: client["exulu"]
|
|
@@ -72,25 +79,30 @@ import "pgvector/knex";
|
|
|
72
79
|
var db = {};
|
|
73
80
|
async function postgresClient() {
|
|
74
81
|
if (!db["exulu"]) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
82
|
+
try {
|
|
83
|
+
console.log("[EXULU] Initializing exulu database.");
|
|
84
|
+
console.log(process.env.POSTGRES_DB_HOST);
|
|
85
|
+
console.log(process.env.POSTGRES_DB_PORT);
|
|
86
|
+
console.log(process.env.POSTGRES_DB_USER);
|
|
87
|
+
console.log(process.env.POSTGRES_DB_PASSWORD);
|
|
88
|
+
console.log(process.env.POSTGRES_DB_SSL);
|
|
89
|
+
const knex = Knex({
|
|
90
|
+
client: "pg",
|
|
91
|
+
connection: {
|
|
92
|
+
host: process.env.POSTGRES_DB_HOST,
|
|
93
|
+
port: parseInt(process.env.POSTGRES_DB_PORT || "5432"),
|
|
94
|
+
user: process.env.POSTGRES_DB_USER,
|
|
95
|
+
database: "exulu",
|
|
96
|
+
password: process.env.POSTGRES_DB_PASSWORD,
|
|
97
|
+
ssl: process.env.POSTGRES_DB_SSL === "true" ? { rejectUnauthorized: false } : false
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
await knex.schema.createExtensionIfNotExists("vector");
|
|
101
|
+
db["exulu"] = knex;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error("[EXULU] Error initializing exulu database.", error);
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
94
106
|
}
|
|
95
107
|
return {
|
|
96
108
|
db: db["exulu"]
|
|
@@ -357,6 +369,7 @@ var sanitizeName = (name) => {
|
|
|
357
369
|
};
|
|
358
370
|
|
|
359
371
|
// src/postgres/init-db.ts
|
|
372
|
+
import bcrypt from "bcryptjs";
|
|
360
373
|
var up = async function(knex) {
|
|
361
374
|
if (!await knex.schema.hasTable("roles")) {
|
|
362
375
|
await knex.schema.createTable("roles", (table) => {
|
|
@@ -504,6 +517,11 @@ var up = async function(knex) {
|
|
|
504
517
|
});
|
|
505
518
|
}
|
|
506
519
|
};
|
|
520
|
+
var SALT_ROUNDS = 12;
|
|
521
|
+
async function encryptApiKey(apikey) {
|
|
522
|
+
const hash = await bcrypt.hash(apikey, SALT_ROUNDS);
|
|
523
|
+
return hash;
|
|
524
|
+
}
|
|
507
525
|
var execute = async () => {
|
|
508
526
|
console.log("[EXULU] Initializing database.");
|
|
509
527
|
const { db: db2 } = await postgresClient();
|
|
@@ -522,6 +540,10 @@ var execute = async () => {
|
|
|
522
540
|
} else {
|
|
523
541
|
roleId = existingRole.id;
|
|
524
542
|
}
|
|
543
|
+
const newKeyName = "exulu_default_key";
|
|
544
|
+
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
545
|
+
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
546
|
+
const encryptedKey = await encryptApiKey(plainKey);
|
|
525
547
|
const existingUser = await db2.from("users").where({ email: "admin@exulu.com" }).first();
|
|
526
548
|
if (!existingUser) {
|
|
527
549
|
console.log("[EXULU] Creating default admin user.");
|
|
@@ -531,11 +553,28 @@ var execute = async () => {
|
|
|
531
553
|
super_admin: true,
|
|
532
554
|
createdAt: /* @__PURE__ */ new Date(),
|
|
533
555
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
556
|
+
type: "user",
|
|
557
|
+
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
558
|
+
role: roleId
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
const existingApiUser = await db2.from("users").where({ email: "api@exulu.com" }).first();
|
|
562
|
+
if (!existingApiUser) {
|
|
563
|
+
console.log("[EXULU] Creating default api user.");
|
|
564
|
+
await db2.from("users").insert({
|
|
565
|
+
name: "exulu",
|
|
566
|
+
email: "admin@exulu.com",
|
|
567
|
+
super_admin: true,
|
|
568
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
569
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
570
|
+
type: "api",
|
|
571
|
+
apikey: `${encryptedKey}${postFix}`,
|
|
534
572
|
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
535
573
|
role: roleId
|
|
536
574
|
});
|
|
537
575
|
}
|
|
538
576
|
console.log("[EXULU] Database initialized.");
|
|
577
|
+
console.log("[EXULU] Default api key: ", `${encryptedKey}${postFix}`);
|
|
539
578
|
return;
|
|
540
579
|
};
|
|
541
580
|
|
|
@@ -1387,7 +1426,7 @@ import "express";
|
|
|
1387
1426
|
import { getToken } from "next-auth/jwt";
|
|
1388
1427
|
|
|
1389
1428
|
// src/auth/auth.ts
|
|
1390
|
-
import
|
|
1429
|
+
import bcrypt2 from "bcryptjs";
|
|
1391
1430
|
var authentication = async ({
|
|
1392
1431
|
apikey,
|
|
1393
1432
|
authtoken,
|
|
@@ -1478,11 +1517,11 @@ var authentication = async ({
|
|
|
1478
1517
|
code: 401
|
|
1479
1518
|
};
|
|
1480
1519
|
}
|
|
1481
|
-
const filtered = users.filter(({
|
|
1520
|
+
const filtered = users.filter(({ apikey: apikey2, id }) => apikey2.includes(keyName));
|
|
1482
1521
|
for (const user of filtered) {
|
|
1483
|
-
const lastSlashIndex = user.
|
|
1484
|
-
const compareValue = lastSlashIndex !== -1 ? user.
|
|
1485
|
-
const isMatch = await
|
|
1522
|
+
const lastSlashIndex = user.apikey.lastIndexOf("/");
|
|
1523
|
+
const compareValue = lastSlashIndex !== -1 ? user.apikey.substring(0, lastSlashIndex) : user.apikey;
|
|
1524
|
+
const isMatch = await bcrypt2.compare(keyValue, compareValue);
|
|
1486
1525
|
if (isMatch) {
|
|
1487
1526
|
await db2.from("users").where({ id: user.id }).update({
|
|
1488
1527
|
lastUsed: /* @__PURE__ */ new Date()
|
|
@@ -1673,6 +1712,10 @@ var ExuluQueues = class {
|
|
|
1673
1712
|
if (existing) {
|
|
1674
1713
|
return existing;
|
|
1675
1714
|
}
|
|
1715
|
+
if (!redisServer.host?.length || !redisServer.port?.length) {
|
|
1716
|
+
console.error(`[EXULU] no redis server configured, but you are trying to use a queue ( ${name}), likely in an agent or workflow (look for ExuluQueues.use() ).`);
|
|
1717
|
+
throw new Error(`[EXULU] no redis server configured.`);
|
|
1718
|
+
}
|
|
1676
1719
|
const newQueue = new Queue3(`${name}`, { connection: redisServer });
|
|
1677
1720
|
this.queues.push(newQueue);
|
|
1678
1721
|
return newQueue;
|
|
@@ -2092,9 +2135,6 @@ var createUppyRoutes = async (app) => {
|
|
|
2092
2135
|
return stsClient;
|
|
2093
2136
|
}
|
|
2094
2137
|
app.use(bodyParser.urlencoded({ extended: true }), bodyParser.json());
|
|
2095
|
-
app.get("/", (req, res) => {
|
|
2096
|
-
res.json("Exulu upload server.");
|
|
2097
|
-
});
|
|
2098
2138
|
app.get("/s3/list", async (req, res, next) => {
|
|
2099
2139
|
const apikey = req.headers["exulu-api-key"] || null;
|
|
2100
2140
|
let authtoken = null;
|
|
@@ -2521,7 +2561,11 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2521
2561
|
{ route: "/items/export/:context", method: "GET", note: "Export items from context" },
|
|
2522
2562
|
{ route: "/graphql", method: "POST", note: "GraphQL endpoint" }
|
|
2523
2563
|
);
|
|
2524
|
-
|
|
2564
|
+
if (redisServer.host?.length && redisServer.port?.length) {
|
|
2565
|
+
await createRecurringJobs();
|
|
2566
|
+
} else {
|
|
2567
|
+
console.log("===========================", "[EXULU] no redis server configured, not setting up recurring jobs.", "===========================");
|
|
2568
|
+
}
|
|
2525
2569
|
const schema = createSDL([usersSchema, rolesSchema, agentsSchema, jobsSchema]);
|
|
2526
2570
|
const server = new ApolloServer({ schema, introspection: true });
|
|
2527
2571
|
await server.start();
|
|
@@ -2581,7 +2625,6 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2581
2625
|
}
|
|
2582
2626
|
});
|
|
2583
2627
|
});
|
|
2584
|
-
console.log("tools", tools);
|
|
2585
2628
|
app.get("/tools", async (req, res) => {
|
|
2586
2629
|
res.status(200).json(tools.map((tool) => ({
|
|
2587
2630
|
id: tool.id,
|
|
@@ -3242,6 +3285,7 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
3242
3285
|
return;
|
|
3243
3286
|
}
|
|
3244
3287
|
if (agent.rateLimit) {
|
|
3288
|
+
console.log("[EXULU] rate limiting agent.", agent.rateLimit);
|
|
3245
3289
|
const limit = await rateLimiter(
|
|
3246
3290
|
agent.rateLimit.name || agent.id,
|
|
3247
3291
|
agent.rateLimit.rate_limit.time,
|