@exulu/backend 1.32.1 → 1.34.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/.mcp.json +11 -0
- package/CHANGELOG.md +3 -3
- package/dist/index.cjs +914 -240
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +914 -240
- package/package.json +1 -1
- package/types/models/context.ts +26 -12
- package/types/models/eval-run.ts +7 -4
package/dist/index.cjs
CHANGED
|
@@ -48,7 +48,7 @@ __export(index_exports, {
|
|
|
48
48
|
ExuluUtils: () => ExuluUtils,
|
|
49
49
|
ExuluVariables: () => ExuluVariables,
|
|
50
50
|
db: () => db2,
|
|
51
|
-
logMetadata: () =>
|
|
51
|
+
logMetadata: () => logMetadata2
|
|
52
52
|
});
|
|
53
53
|
module.exports = __toCommonJS(index_exports);
|
|
54
54
|
var import_config = require("dotenv/config");
|
|
@@ -58,10 +58,10 @@ var import_redis = require("redis");
|
|
|
58
58
|
|
|
59
59
|
// src/bullmq/server.ts
|
|
60
60
|
var redisServer = {
|
|
61
|
-
host:
|
|
62
|
-
port: process.env.REDIS_PORT,
|
|
61
|
+
host: process.env.REDIS_HOST ?? "",
|
|
62
|
+
port: process.env.REDIS_PORT ?? "",
|
|
63
63
|
password: process.env.REDIS_PASSWORD || void 0,
|
|
64
|
-
username: process.env.REDIS_USER ||
|
|
64
|
+
username: process.env.REDIS_USER || ""
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
// src/redis/client.ts
|
|
@@ -74,7 +74,7 @@ async function redisClient() {
|
|
|
74
74
|
if (!client["exulu"]) {
|
|
75
75
|
try {
|
|
76
76
|
let url = "";
|
|
77
|
-
if (redisServer.
|
|
77
|
+
if (redisServer.password) {
|
|
78
78
|
url = `redis://${redisServer.username}:${redisServer.password}@${redisServer.host}:${redisServer.port}`;
|
|
79
79
|
} else {
|
|
80
80
|
url = `redis://${redisServer.host}:${redisServer.port}`;
|
|
@@ -279,7 +279,7 @@ var bullmqDecorator = async ({
|
|
|
279
279
|
embedder,
|
|
280
280
|
workflow,
|
|
281
281
|
processor,
|
|
282
|
-
|
|
282
|
+
evaluation
|
|
283
283
|
];
|
|
284
284
|
if (types.filter((type2) => type2).length > 1) {
|
|
285
285
|
throw new Error("Cannot have multiple types in the same job, must be one of the following: embedder, workflow, processor or eval.");
|
|
@@ -434,7 +434,7 @@ var mapType = (t, type, name, defaultValue, unique) => {
|
|
|
434
434
|
if (unique) t.unique(name);
|
|
435
435
|
return;
|
|
436
436
|
}
|
|
437
|
-
throw new Error("Invalid type: " + type);
|
|
437
|
+
throw new Error("Invalid field type for database: " + type);
|
|
438
438
|
};
|
|
439
439
|
|
|
440
440
|
// src/registry/utils/sanitize-name.ts
|
|
@@ -824,6 +824,10 @@ var agentSessionsSchema = {
|
|
|
824
824
|
name: "project",
|
|
825
825
|
type: "uuid",
|
|
826
826
|
required: false
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
name: "metadata",
|
|
830
|
+
type: "json"
|
|
827
831
|
}
|
|
828
832
|
]
|
|
829
833
|
};
|
|
@@ -1375,6 +1379,69 @@ var platformConfigurationsSchema = {
|
|
|
1375
1379
|
}
|
|
1376
1380
|
]
|
|
1377
1381
|
};
|
|
1382
|
+
var promptLibrarySchema = {
|
|
1383
|
+
type: "prompt_library",
|
|
1384
|
+
name: {
|
|
1385
|
+
plural: "prompt_library",
|
|
1386
|
+
singular: "prompt_library_item"
|
|
1387
|
+
},
|
|
1388
|
+
RBAC: true,
|
|
1389
|
+
fields: [
|
|
1390
|
+
{
|
|
1391
|
+
name: "name",
|
|
1392
|
+
type: "text",
|
|
1393
|
+
required: true
|
|
1394
|
+
},
|
|
1395
|
+
{
|
|
1396
|
+
name: "description",
|
|
1397
|
+
type: "text"
|
|
1398
|
+
},
|
|
1399
|
+
{
|
|
1400
|
+
name: "content",
|
|
1401
|
+
type: "longText",
|
|
1402
|
+
required: true
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
name: "tags",
|
|
1406
|
+
type: "json"
|
|
1407
|
+
},
|
|
1408
|
+
{
|
|
1409
|
+
name: "usage_count",
|
|
1410
|
+
type: "number",
|
|
1411
|
+
default: 0
|
|
1412
|
+
},
|
|
1413
|
+
{
|
|
1414
|
+
name: "favorite_count",
|
|
1415
|
+
type: "number",
|
|
1416
|
+
default: 0
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
name: "assigned_agents",
|
|
1420
|
+
type: "json"
|
|
1421
|
+
}
|
|
1422
|
+
]
|
|
1423
|
+
};
|
|
1424
|
+
var promptFavoritesSchema = {
|
|
1425
|
+
type: "prompt_favorites",
|
|
1426
|
+
name: {
|
|
1427
|
+
plural: "prompt_favorites",
|
|
1428
|
+
singular: "prompt_favorite"
|
|
1429
|
+
},
|
|
1430
|
+
fields: [
|
|
1431
|
+
{
|
|
1432
|
+
name: "user_id",
|
|
1433
|
+
type: "number",
|
|
1434
|
+
required: true,
|
|
1435
|
+
index: true
|
|
1436
|
+
},
|
|
1437
|
+
{
|
|
1438
|
+
name: "prompt_id",
|
|
1439
|
+
type: "uuid",
|
|
1440
|
+
required: true,
|
|
1441
|
+
index: true
|
|
1442
|
+
}
|
|
1443
|
+
]
|
|
1444
|
+
};
|
|
1378
1445
|
var addCoreFields = (schema) => {
|
|
1379
1446
|
schema.fields.forEach((field) => {
|
|
1380
1447
|
if (field.type === "file") {
|
|
@@ -1418,7 +1485,9 @@ var coreSchemas = {
|
|
|
1418
1485
|
rbacSchema: () => addCoreFields(rbacSchema),
|
|
1419
1486
|
workflowTemplatesSchema: () => addCoreFields(workflowTemplatesSchema),
|
|
1420
1487
|
platformConfigurationsSchema: () => addCoreFields(platformConfigurationsSchema),
|
|
1421
|
-
jobResultsSchema: () => addCoreFields(jobResultsSchema)
|
|
1488
|
+
jobResultsSchema: () => addCoreFields(jobResultsSchema),
|
|
1489
|
+
promptLibrarySchema: () => addCoreFields(promptLibrarySchema),
|
|
1490
|
+
promptFavoritesSchema: () => addCoreFields(promptFavoritesSchema)
|
|
1422
1491
|
};
|
|
1423
1492
|
}
|
|
1424
1493
|
};
|
|
@@ -1481,11 +1550,11 @@ var bullmq = {
|
|
|
1481
1550
|
if (!data.inputs) {
|
|
1482
1551
|
throw new Error(`Missing property "inputs" in data for job ${id}.`);
|
|
1483
1552
|
}
|
|
1484
|
-
if (data.type !== "embedder" && data.type !== "workflow" && data.type !== "processor" && data.type !== "eval_run" && data.type !== "eval_function") {
|
|
1485
|
-
throw new Error(`Property "type" in data for job ${id} must be of value "embedder", "workflow", "processor", "eval_run" or "
|
|
1553
|
+
if (data.type !== "embedder" && data.type !== "workflow" && data.type !== "processor" && data.type !== "eval_run" && data.type !== "eval_function" && data.type !== "source") {
|
|
1554
|
+
throw new Error(`Property "type" in data for job ${id} must be of value "embedder", "workflow", "processor", "eval_run", "eval_function" or "source".`);
|
|
1486
1555
|
}
|
|
1487
|
-
if (!data.workflow && !data.embedder && !data.processor && !data.eval_run_id && !data.eval_functions?.length) {
|
|
1488
|
-
throw new Error(`Either a workflow, embedder, processor, eval_run or
|
|
1556
|
+
if (!data.workflow && !data.embedder && !data.processor && !data.eval_run_id && !data.eval_functions?.length && !data.source) {
|
|
1557
|
+
throw new Error(`Either a workflow, embedder, processor, eval_run, eval_functions or source must be set for job ${id}.`);
|
|
1489
1558
|
}
|
|
1490
1559
|
}
|
|
1491
1560
|
};
|
|
@@ -1878,6 +1947,7 @@ input FilterOperatorJSON {
|
|
|
1878
1947
|
eq: JSON
|
|
1879
1948
|
ne: JSON
|
|
1880
1949
|
in: [JSON]
|
|
1950
|
+
contains: JSON
|
|
1881
1951
|
}
|
|
1882
1952
|
|
|
1883
1953
|
input SortBy {
|
|
@@ -1991,6 +2061,7 @@ var handleRBACUpdate = async (db3, entityName, resourceId, rbacData, existingRba
|
|
|
1991
2061
|
};
|
|
1992
2062
|
function createMutations(table, agents, contexts, tools, config) {
|
|
1993
2063
|
const tableNamePlural = table.name.plural.toLowerCase();
|
|
2064
|
+
const tableNameSingular = table.name.singular.toLowerCase();
|
|
1994
2065
|
const validateWriteAccess = async (id, context) => {
|
|
1995
2066
|
try {
|
|
1996
2067
|
const { db: db3, req, user } = context;
|
|
@@ -2302,56 +2373,131 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2302
2373
|
return finalizeRequestedFields({ table, requestedFields, agents, contexts, tools, result, user: context.user.id });
|
|
2303
2374
|
}
|
|
2304
2375
|
};
|
|
2305
|
-
if (table.type === "items"
|
|
2306
|
-
|
|
2376
|
+
if (table.type === "items") {
|
|
2377
|
+
if (table.fields.some((field) => field.processor?.execute)) {
|
|
2378
|
+
mutations[`${tableNameSingular}ProcessItemField`] = async (_, args, context, info) => {
|
|
2379
|
+
if (!context.user?.super_admin) {
|
|
2380
|
+
throw new Error("You are not authorized to process fields via API, user must be super admin.");
|
|
2381
|
+
}
|
|
2382
|
+
const exists = contexts.find((context2) => context2.id === table.id);
|
|
2383
|
+
if (!exists) {
|
|
2384
|
+
throw new Error(`Context ${table.id} not found.`);
|
|
2385
|
+
}
|
|
2386
|
+
if (!args.field) {
|
|
2387
|
+
throw new Error("Field argument missing, the field argument is required.");
|
|
2388
|
+
}
|
|
2389
|
+
if (!args.item) {
|
|
2390
|
+
throw new Error("Item argument missing, the item argument is required.");
|
|
2391
|
+
}
|
|
2392
|
+
const name = args.field?.replace("_s3key", "");
|
|
2393
|
+
console.log("[EXULU] name", name);
|
|
2394
|
+
console.log("[EXULU] fields", exists.fields.map((field2) => field2.name));
|
|
2395
|
+
const field = exists.fields.find((field2) => field2.name === name);
|
|
2396
|
+
if (!field) {
|
|
2397
|
+
throw new Error(`Field ${name} not found in context ${exists.id}.`);
|
|
2398
|
+
}
|
|
2399
|
+
if (!field.processor) {
|
|
2400
|
+
throw new Error(`Processor not set for field ${args.field} in context ${exists.id}.`);
|
|
2401
|
+
}
|
|
2402
|
+
const { db: db3 } = context;
|
|
2403
|
+
let query = db3.from(tableNamePlural).select("*").where({ id: args.item });
|
|
2404
|
+
query = applyAccessControl(table, context.user, query);
|
|
2405
|
+
const item = await query.first();
|
|
2406
|
+
if (!item) {
|
|
2407
|
+
throw new Error("Item not found, or your user does not have access to it.");
|
|
2408
|
+
}
|
|
2409
|
+
const { job, result } = await exists.processField(
|
|
2410
|
+
"api",
|
|
2411
|
+
context.user.id,
|
|
2412
|
+
context.user.role?.id,
|
|
2413
|
+
{
|
|
2414
|
+
...item,
|
|
2415
|
+
field: args.field
|
|
2416
|
+
},
|
|
2417
|
+
config
|
|
2418
|
+
);
|
|
2419
|
+
return {
|
|
2420
|
+
message: job ? "Processing job scheduled." : "Item processed successfully.",
|
|
2421
|
+
result,
|
|
2422
|
+
job
|
|
2423
|
+
};
|
|
2424
|
+
};
|
|
2425
|
+
}
|
|
2426
|
+
mutations[`${tableNameSingular}ExecuteSource`] = async (_, args, context, info) => {
|
|
2427
|
+
console.log("[EXULU] Executing source", args);
|
|
2307
2428
|
if (!context.user?.super_admin) {
|
|
2308
|
-
throw new Error("You are not authorized to
|
|
2429
|
+
throw new Error("You are not authorized to execute sources via API, user must be super admin.");
|
|
2430
|
+
}
|
|
2431
|
+
if (!args.source) {
|
|
2432
|
+
throw new Error("Source argument missing, the source argument is required.");
|
|
2309
2433
|
}
|
|
2310
2434
|
const exists = contexts.find((context2) => context2.id === table.id);
|
|
2311
2435
|
if (!exists) {
|
|
2312
2436
|
throw new Error(`Context ${table.id} not found.`);
|
|
2313
2437
|
}
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
if (!args.item) {
|
|
2318
|
-
throw new Error("Item argument missing, the item argument is required.");
|
|
2319
|
-
}
|
|
2320
|
-
const name = args.field?.replace("_s3key", "");
|
|
2321
|
-
console.log("[EXULU] name", name);
|
|
2322
|
-
console.log("[EXULU] fields", exists.fields.map((field2) => field2.name));
|
|
2323
|
-
const field = exists.fields.find((field2) => field2.name === name);
|
|
2324
|
-
if (!field) {
|
|
2325
|
-
throw new Error(`Field ${name} not found in context ${exists.id}.`);
|
|
2438
|
+
const source = exists.sources.find((source2) => source2.id === args.source);
|
|
2439
|
+
if (!source) {
|
|
2440
|
+
throw new Error(`Source ${args.source} not found in context ${exists.id}.`);
|
|
2326
2441
|
}
|
|
2327
|
-
if (
|
|
2328
|
-
|
|
2442
|
+
if (source?.config?.queue) {
|
|
2443
|
+
console.log("[EXULU] Executing source function in queue mode");
|
|
2444
|
+
const queue = await source.config.queue;
|
|
2445
|
+
if (!queue) {
|
|
2446
|
+
throw new Error(`Queue not found for source ${source.id}.`);
|
|
2447
|
+
}
|
|
2448
|
+
const job = await queue.queue?.add(source.id, {
|
|
2449
|
+
source: source.id,
|
|
2450
|
+
context: exists.id,
|
|
2451
|
+
type: "source",
|
|
2452
|
+
inputs: args.inputs,
|
|
2453
|
+
user: context.user.id,
|
|
2454
|
+
role: context.user.role?.id
|
|
2455
|
+
});
|
|
2456
|
+
console.log("[EXULU] Source function job scheduled", job.id);
|
|
2457
|
+
return {
|
|
2458
|
+
message: "Job scheduled for source execution.",
|
|
2459
|
+
jobs: [job?.id],
|
|
2460
|
+
items: []
|
|
2461
|
+
};
|
|
2329
2462
|
}
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2463
|
+
console.log("[EXULU] Executing source function directly");
|
|
2464
|
+
const result = await source.execute(args.inputs);
|
|
2465
|
+
let jobs = [];
|
|
2466
|
+
let items = [];
|
|
2467
|
+
for (const item of result) {
|
|
2468
|
+
const { item: createdItem, job } = await exists.createItem(
|
|
2469
|
+
item,
|
|
2470
|
+
config,
|
|
2471
|
+
context.user.id,
|
|
2472
|
+
context.user.role?.id
|
|
2473
|
+
);
|
|
2474
|
+
if (job) {
|
|
2475
|
+
jobs.push(job);
|
|
2476
|
+
console.log(`[EXULU] Scheduled job through source update job for item ${createdItem.id} (Job ID: ${job})`);
|
|
2477
|
+
}
|
|
2478
|
+
if (createdItem.id) {
|
|
2479
|
+
items.push(createdItem.id);
|
|
2480
|
+
console.log(`[EXULU] created item through source update job ${createdItem.id}`);
|
|
2481
|
+
}
|
|
2336
2482
|
}
|
|
2337
|
-
|
|
2338
|
-
"
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
);
|
|
2483
|
+
await updateStatistic({
|
|
2484
|
+
name: "count",
|
|
2485
|
+
label: source.id,
|
|
2486
|
+
type: STATISTICS_TYPE_ENUM.SOURCE_UPDATE,
|
|
2487
|
+
trigger: "api",
|
|
2488
|
+
count: 1,
|
|
2489
|
+
user: context?.user?.id,
|
|
2490
|
+
role: context?.user?.role?.id
|
|
2491
|
+
});
|
|
2347
2492
|
return {
|
|
2348
|
-
message:
|
|
2349
|
-
|
|
2350
|
-
|
|
2493
|
+
message: "Items created successfully.",
|
|
2494
|
+
jobs,
|
|
2495
|
+
items
|
|
2351
2496
|
};
|
|
2352
|
-
}
|
|
2497
|
+
};
|
|
2498
|
+
mutations[`${tableNameSingular}GenerateChunks`] = async (_, args, context, info) => {
|
|
2353
2499
|
if (!context.user?.super_admin) {
|
|
2354
|
-
throw new Error("You are not authorized to
|
|
2500
|
+
throw new Error("You are not authorized to generate chunks via API, user must be super admin.");
|
|
2355
2501
|
}
|
|
2356
2502
|
const { db: db3 } = await postgresClient();
|
|
2357
2503
|
const exists = contexts.find((context2) => context2.id === table.id);
|
|
@@ -2377,7 +2523,7 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2377
2523
|
jobs: jobs2.slice(0, 100)
|
|
2378
2524
|
};
|
|
2379
2525
|
}
|
|
2380
|
-
query = applyFilters(query, args.where);
|
|
2526
|
+
query = applyFilters(query, args.where, table);
|
|
2381
2527
|
const items = await query;
|
|
2382
2528
|
if (items.length === 0) {
|
|
2383
2529
|
throw new Error("No items found to generate chunks for.");
|
|
@@ -2396,11 +2542,12 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2396
2542
|
}
|
|
2397
2543
|
}
|
|
2398
2544
|
return {
|
|
2399
|
-
message: "Chunks
|
|
2545
|
+
message: "Chunks generated successfully.",
|
|
2400
2546
|
items: items.length,
|
|
2401
2547
|
jobs: jobs.slice(0, 100)
|
|
2402
2548
|
};
|
|
2403
|
-
}
|
|
2549
|
+
};
|
|
2550
|
+
mutations[`${tableNameSingular}DeleteChunks`] = async (_, args, context, info) => {
|
|
2404
2551
|
if (!context.user?.super_admin) {
|
|
2405
2552
|
throw new Error("You are not authorized to delete chunks via API, user must be super admin.");
|
|
2406
2553
|
}
|
|
@@ -2411,7 +2558,7 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2411
2558
|
}
|
|
2412
2559
|
let query = db3.from(getTableName(id)).select("id");
|
|
2413
2560
|
if (args.where) {
|
|
2414
|
-
query = applyFilters(query, args.where);
|
|
2561
|
+
query = applyFilters(query, args.where, table);
|
|
2415
2562
|
}
|
|
2416
2563
|
const items = await query;
|
|
2417
2564
|
if (items.length === 0) {
|
|
@@ -2468,18 +2615,38 @@ var applyAccessControl = (table, user, query) => {
|
|
|
2468
2615
|
}
|
|
2469
2616
|
return query;
|
|
2470
2617
|
};
|
|
2471
|
-
var converOperatorToQuery = (query, fieldName, operators) => {
|
|
2618
|
+
var converOperatorToQuery = (query, fieldName, operators, table) => {
|
|
2619
|
+
const field = table?.fields.find((f) => f.name === fieldName);
|
|
2620
|
+
const isJsonField = field?.type === "json";
|
|
2472
2621
|
if (operators.eq !== void 0) {
|
|
2473
|
-
|
|
2622
|
+
if (isJsonField) {
|
|
2623
|
+
query = query.whereRaw(`?? = ?::jsonb`, [fieldName, JSON.stringify(operators.eq)]);
|
|
2624
|
+
} else {
|
|
2625
|
+
query = query.where(fieldName, operators.eq);
|
|
2626
|
+
}
|
|
2474
2627
|
}
|
|
2475
2628
|
if (operators.ne !== void 0) {
|
|
2476
|
-
|
|
2629
|
+
if (isJsonField) {
|
|
2630
|
+
query = query.whereRaw(`?? IS DISTINCT FROM ?::jsonb`, [fieldName, JSON.stringify(operators.ne)]);
|
|
2631
|
+
} else {
|
|
2632
|
+
query = query.whereRaw(`?? IS DISTINCT FROM ?`, [fieldName, operators.ne]);
|
|
2633
|
+
}
|
|
2477
2634
|
}
|
|
2478
2635
|
if (operators.in !== void 0) {
|
|
2479
|
-
|
|
2636
|
+
if (isJsonField) {
|
|
2637
|
+
const conditions = operators.in.map((val) => `?? = ?::jsonb`).join(" OR ");
|
|
2638
|
+
const bindings = operators.in.flatMap((val) => [fieldName, JSON.stringify(val)]);
|
|
2639
|
+
query = query.whereRaw(`(${conditions})`, bindings);
|
|
2640
|
+
} else {
|
|
2641
|
+
query = query.whereIn(fieldName, operators.in);
|
|
2642
|
+
}
|
|
2480
2643
|
}
|
|
2481
2644
|
if (operators.contains !== void 0) {
|
|
2482
|
-
|
|
2645
|
+
if (isJsonField) {
|
|
2646
|
+
query = query.whereRaw(`?? @> ?::jsonb`, [fieldName, JSON.stringify(operators.contains)]);
|
|
2647
|
+
} else {
|
|
2648
|
+
query = query.where(fieldName, "like", `%${operators.contains}%`);
|
|
2649
|
+
}
|
|
2483
2650
|
}
|
|
2484
2651
|
if (operators.lte !== void 0) {
|
|
2485
2652
|
query = query.where(fieldName, "<=", operators.lte);
|
|
@@ -2741,21 +2908,21 @@ var finalizeRequestedFields = async ({
|
|
|
2741
2908
|
}
|
|
2742
2909
|
return result;
|
|
2743
2910
|
};
|
|
2744
|
-
var applyFilters = (query, filters) => {
|
|
2911
|
+
var applyFilters = (query, filters, table) => {
|
|
2745
2912
|
filters.forEach((filter) => {
|
|
2746
2913
|
Object.entries(filter).forEach(([fieldName, operators]) => {
|
|
2747
2914
|
if (operators) {
|
|
2748
2915
|
if (operators.and !== void 0) {
|
|
2749
2916
|
operators.and.forEach((operator) => {
|
|
2750
|
-
query = converOperatorToQuery(query, fieldName, operator);
|
|
2917
|
+
query = converOperatorToQuery(query, fieldName, operator, table);
|
|
2751
2918
|
});
|
|
2752
2919
|
}
|
|
2753
2920
|
if (operators.or !== void 0) {
|
|
2754
2921
|
operators.or.forEach((operator) => {
|
|
2755
|
-
query = converOperatorToQuery(query, fieldName, operator);
|
|
2922
|
+
query = converOperatorToQuery(query, fieldName, operator, table);
|
|
2756
2923
|
});
|
|
2757
2924
|
}
|
|
2758
|
-
query = converOperatorToQuery(query, fieldName, operators);
|
|
2925
|
+
query = converOperatorToQuery(query, fieldName, operators, table);
|
|
2759
2926
|
}
|
|
2760
2927
|
});
|
|
2761
2928
|
});
|
|
@@ -2795,7 +2962,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2795
2962
|
const requestedFields = getRequestedFields(info);
|
|
2796
2963
|
const sanitizedFields = sanitizeRequestedFields(table, requestedFields);
|
|
2797
2964
|
let query = db3.from(tableNamePlural).select(sanitizedFields);
|
|
2798
|
-
query = applyFilters(query, filters);
|
|
2965
|
+
query = applyFilters(query, filters, table);
|
|
2799
2966
|
query = applyAccessControl(table, context.user, query);
|
|
2800
2967
|
query = applySorting(query, sort);
|
|
2801
2968
|
let result = await query.first();
|
|
@@ -2808,7 +2975,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2808
2975
|
throw new Error("Limit cannot be greater than 500.");
|
|
2809
2976
|
}
|
|
2810
2977
|
let countQuery = db3(tableNamePlural);
|
|
2811
|
-
countQuery = applyFilters(countQuery, filters);
|
|
2978
|
+
countQuery = applyFilters(countQuery, filters, table);
|
|
2812
2979
|
countQuery = applyAccessControl(table, context.user, countQuery);
|
|
2813
2980
|
const countResult = await countQuery.count("* as count");
|
|
2814
2981
|
const itemCount = Number(countResult[0]?.count || 0);
|
|
@@ -2817,7 +2984,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2817
2984
|
const hasPreviousPage = currentPage > 1;
|
|
2818
2985
|
const hasNextPage = currentPage < pageCount - 1;
|
|
2819
2986
|
let dataQuery = db3(tableNamePlural);
|
|
2820
|
-
dataQuery = applyFilters(dataQuery, filters);
|
|
2987
|
+
dataQuery = applyFilters(dataQuery, filters, table);
|
|
2821
2988
|
dataQuery = applyAccessControl(table, context.user, dataQuery);
|
|
2822
2989
|
const requestedFields = getRequestedFields(info);
|
|
2823
2990
|
dataQuery = applySorting(dataQuery, sort);
|
|
@@ -2842,7 +3009,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2842
3009
|
const { filters = [], groupBy } = args;
|
|
2843
3010
|
const { db: db3 } = context;
|
|
2844
3011
|
let query = db3(tableNamePlural);
|
|
2845
|
-
query = applyFilters(query, filters);
|
|
3012
|
+
query = applyFilters(query, filters, table);
|
|
2846
3013
|
query = applyAccessControl(table, context.user, query);
|
|
2847
3014
|
if (groupBy) {
|
|
2848
3015
|
query = query.select(groupBy).groupBy(groupBy);
|
|
@@ -2942,11 +3109,11 @@ var vectorSearch = async ({
|
|
|
2942
3109
|
const mainTable = getTableName(id);
|
|
2943
3110
|
const chunksTable = getChunksTableName(id);
|
|
2944
3111
|
let countQuery = db3(mainTable);
|
|
2945
|
-
countQuery = applyFilters(countQuery, filters);
|
|
3112
|
+
countQuery = applyFilters(countQuery, filters, table);
|
|
2946
3113
|
countQuery = applyAccessControl(table, user, countQuery);
|
|
2947
3114
|
const columns = await db3(mainTable).columnInfo();
|
|
2948
3115
|
let itemsQuery = db3(mainTable).select(Object.keys(columns).map((column) => mainTable + "." + column));
|
|
2949
|
-
itemsQuery = applyFilters(itemsQuery, filters);
|
|
3116
|
+
itemsQuery = applyFilters(itemsQuery, filters, table);
|
|
2950
3117
|
itemsQuery = applyAccessControl(table, user, itemsQuery);
|
|
2951
3118
|
itemsQuery = applySorting(itemsQuery, sort);
|
|
2952
3119
|
if (queryRewriter) {
|
|
@@ -3372,6 +3539,7 @@ function createSDL(tables, contexts, agents, tools, config, evals, queues2) {
|
|
|
3372
3539
|
if (table.type === "items") {
|
|
3373
3540
|
mutationDefs += `
|
|
3374
3541
|
${tableNameSingular}GenerateChunks(where: [Filter${tableNameSingularUpperCaseFirst}]): ${tableNameSingular}GenerateChunksReturnPayload
|
|
3542
|
+
${tableNameSingular}ExecuteSource(source: ID!, inputs: JSON!): ${tableNameSingular}ExecuteSourceReturnPayload
|
|
3375
3543
|
${tableNameSingular}DeleteChunks(where: [Filter${tableNameSingularUpperCaseFirst}]): ${tableNameSingular}DeleteChunksReturnPayload
|
|
3376
3544
|
`;
|
|
3377
3545
|
if (processorFields?.length > 0) {
|
|
@@ -3386,6 +3554,12 @@ function createSDL(tables, contexts, agents, tools, config, evals, queues2) {
|
|
|
3386
3554
|
jobs: [String!]
|
|
3387
3555
|
}
|
|
3388
3556
|
|
|
3557
|
+
type ${tableNameSingular}ExecuteSourceReturnPayload {
|
|
3558
|
+
message: String!
|
|
3559
|
+
jobs: [String!]
|
|
3560
|
+
items: [String!]
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3389
3563
|
type ${tableNameSingular}ProcessItemFieldReturnPayload {
|
|
3390
3564
|
message: String!
|
|
3391
3565
|
result: String!
|
|
@@ -3497,7 +3671,7 @@ type PageInfo {
|
|
|
3497
3671
|
toolCategories: [String!]!
|
|
3498
3672
|
`;
|
|
3499
3673
|
typeDefs += `
|
|
3500
|
-
jobs(queue: QueueEnum!, statusses: [JobStateEnum!]): JobPaginationResult
|
|
3674
|
+
jobs(queue: QueueEnum!, statusses: [JobStateEnum!], page: Int, limit: Int): JobPaginationResult
|
|
3501
3675
|
`;
|
|
3502
3676
|
resolvers.Query["providers"] = async (_, args, context, info) => {
|
|
3503
3677
|
const requestedFields = getRequestedFields(info);
|
|
@@ -3696,10 +3870,11 @@ type PageInfo {
|
|
|
3696
3870
|
if (!client2) {
|
|
3697
3871
|
throw new Error("Redis client not created properly");
|
|
3698
3872
|
}
|
|
3873
|
+
console.log("[EXULU] Jobs pagination args", args);
|
|
3699
3874
|
const {
|
|
3700
3875
|
jobs,
|
|
3701
3876
|
count
|
|
3702
|
-
} = await
|
|
3877
|
+
} = await getJobsByQueueName(
|
|
3703
3878
|
args.queue,
|
|
3704
3879
|
args.statusses,
|
|
3705
3880
|
args.page || 1,
|
|
@@ -3728,25 +3903,46 @@ type PageInfo {
|
|
|
3728
3903
|
itemCount: count,
|
|
3729
3904
|
currentPage: args.page || 1,
|
|
3730
3905
|
hasPreviousPage: args.page && args.page > 1 ? true : false,
|
|
3731
|
-
hasNextPage: args.page && args.page < Math.ceil(
|
|
3906
|
+
hasNextPage: args.page && args.page < Math.ceil(count / (args.limit || 100)) ? true : false
|
|
3732
3907
|
}
|
|
3733
3908
|
};
|
|
3734
3909
|
};
|
|
3735
3910
|
resolvers.Query["contexts"] = async (_, args, context, info) => {
|
|
3736
|
-
const data = contexts.map((context2) =>
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
fields: context2.fields.map((field) => {
|
|
3911
|
+
const data = await Promise.all(contexts.map(async (context2) => {
|
|
3912
|
+
const sources = await Promise.all(context2.sources.map(async (source) => {
|
|
3913
|
+
let queueName = void 0;
|
|
3914
|
+
if (source.config) {
|
|
3915
|
+
const config2 = await source.config.queue;
|
|
3916
|
+
queueName = config2?.queue?.name || void 0;
|
|
3917
|
+
}
|
|
3744
3918
|
return {
|
|
3745
|
-
|
|
3746
|
-
name:
|
|
3747
|
-
|
|
3919
|
+
id: source.id,
|
|
3920
|
+
name: source.name,
|
|
3921
|
+
description: source.description,
|
|
3922
|
+
config: {
|
|
3923
|
+
schedule: source.config?.schedule,
|
|
3924
|
+
queue: queueName,
|
|
3925
|
+
retries: source.config?.retries,
|
|
3926
|
+
backoff: source.config?.backoff
|
|
3927
|
+
}
|
|
3748
3928
|
};
|
|
3749
|
-
})
|
|
3929
|
+
}));
|
|
3930
|
+
return {
|
|
3931
|
+
id: context2.id,
|
|
3932
|
+
name: context2.name,
|
|
3933
|
+
description: context2.description,
|
|
3934
|
+
embedder: context2.embedder?.name || void 0,
|
|
3935
|
+
slug: "/contexts/" + context2.id,
|
|
3936
|
+
active: context2.active,
|
|
3937
|
+
sources,
|
|
3938
|
+
fields: context2.fields.map((field) => {
|
|
3939
|
+
return {
|
|
3940
|
+
...field,
|
|
3941
|
+
name: sanitizeName(field.name),
|
|
3942
|
+
label: field.name?.replace("_s3key", "")
|
|
3943
|
+
};
|
|
3944
|
+
})
|
|
3945
|
+
};
|
|
3750
3946
|
}));
|
|
3751
3947
|
const requestedFields = getRequestedFields(info);
|
|
3752
3948
|
return {
|
|
@@ -3764,6 +3960,24 @@ type PageInfo {
|
|
|
3764
3960
|
if (!data) {
|
|
3765
3961
|
return null;
|
|
3766
3962
|
}
|
|
3963
|
+
const sources = await Promise.all(data.sources.map(async (source) => {
|
|
3964
|
+
let queueName = void 0;
|
|
3965
|
+
if (source.config) {
|
|
3966
|
+
const config2 = await source.config.queue;
|
|
3967
|
+
queueName = config2?.queue?.name || void 0;
|
|
3968
|
+
}
|
|
3969
|
+
return {
|
|
3970
|
+
id: source.id,
|
|
3971
|
+
name: source.name,
|
|
3972
|
+
description: source.description,
|
|
3973
|
+
config: {
|
|
3974
|
+
schedule: source.config?.schedule,
|
|
3975
|
+
queue: queueName,
|
|
3976
|
+
retries: source.config?.retries,
|
|
3977
|
+
backoff: source.config?.backoff
|
|
3978
|
+
}
|
|
3979
|
+
};
|
|
3980
|
+
}));
|
|
3767
3981
|
const clean = {
|
|
3768
3982
|
id: data.id,
|
|
3769
3983
|
name: data.name,
|
|
@@ -3771,6 +3985,7 @@ type PageInfo {
|
|
|
3771
3985
|
embedder: data.embedder?.name || void 0,
|
|
3772
3986
|
slug: "/contexts/" + data.id,
|
|
3773
3987
|
active: data.active,
|
|
3988
|
+
sources,
|
|
3774
3989
|
fields: await Promise.all(data.fields.map(async (field) => {
|
|
3775
3990
|
const label = field.name?.replace("_s3key", "");
|
|
3776
3991
|
if (field.type === "file" && !field.name.endsWith("_s3key")) {
|
|
@@ -3987,6 +4202,26 @@ type Context {
|
|
|
3987
4202
|
active: Boolean
|
|
3988
4203
|
fields: JSON
|
|
3989
4204
|
configuration: JSON
|
|
4205
|
+
sources: [ContextSource!]
|
|
4206
|
+
}
|
|
4207
|
+
|
|
4208
|
+
type ContextSource {
|
|
4209
|
+
id: String!
|
|
4210
|
+
name: String!
|
|
4211
|
+
description: String!
|
|
4212
|
+
config: ContextSourceConfig!
|
|
4213
|
+
}
|
|
4214
|
+
|
|
4215
|
+
type ContextSourceConfig {
|
|
4216
|
+
schedule: String
|
|
4217
|
+
queue: String
|
|
4218
|
+
retries: Int
|
|
4219
|
+
backoff: ContextSourceBackoff
|
|
4220
|
+
}
|
|
4221
|
+
|
|
4222
|
+
type ContextSourceBackoff {
|
|
4223
|
+
type: String
|
|
4224
|
+
delay: Int
|
|
3990
4225
|
}
|
|
3991
4226
|
|
|
3992
4227
|
type RunEvalReturnPayload {
|
|
@@ -4072,15 +4307,18 @@ var validateCreateOrRemoveSuperAdminPermission = async (tableNamePlural, input,
|
|
|
4072
4307
|
}
|
|
4073
4308
|
}
|
|
4074
4309
|
};
|
|
4075
|
-
async function
|
|
4310
|
+
async function getJobsByQueueName(queueName, statusses, page, limit) {
|
|
4076
4311
|
const queue = queues.list.get(queueName);
|
|
4077
4312
|
if (!queue) {
|
|
4078
4313
|
throw new Error(`Queue ${queueName} not found`);
|
|
4079
4314
|
}
|
|
4080
4315
|
const config = await queue.use();
|
|
4081
4316
|
const startIndex = (page || 1) - 1;
|
|
4082
|
-
const endIndex = startIndex + (limit || 100);
|
|
4317
|
+
const endIndex = startIndex - 1 + (limit || 100);
|
|
4318
|
+
console.log("[EXULU] Jobs pagination startIndex", startIndex);
|
|
4319
|
+
console.log("[EXULU] Jobs pagination endIndex", endIndex);
|
|
4083
4320
|
const jobs = await config.queue.getJobs(statusses || [], startIndex, endIndex, false);
|
|
4321
|
+
console.log("[EXULU] Jobs pagination jobs", jobs?.length);
|
|
4084
4322
|
const counts = await config.queue.getJobCounts(...statusses || []);
|
|
4085
4323
|
let total = 0;
|
|
4086
4324
|
if (counts) {
|
|
@@ -4651,7 +4889,7 @@ function sanitizeToolName(name) {
|
|
|
4651
4889
|
}
|
|
4652
4890
|
return sanitized;
|
|
4653
4891
|
}
|
|
4654
|
-
var convertToolsArrayToObject = (currentTools, allExuluTools, configs, providerapikey, contexts, user, exuluConfig) => {
|
|
4892
|
+
var convertToolsArrayToObject = (currentTools, allExuluTools, configs, providerapikey, contexts, user, exuluConfig, sessionID) => {
|
|
4655
4893
|
if (!currentTools) return {};
|
|
4656
4894
|
if (!allExuluTools) return {};
|
|
4657
4895
|
const sanitizedTools = currentTools ? currentTools.map((tool2) => ({
|
|
@@ -4661,101 +4899,109 @@ var convertToolsArrayToObject = (currentTools, allExuluTools, configs, providera
|
|
|
4661
4899
|
console.log("[EXULU] Sanitized tools", sanitizedTools.map((x) => x.name + " (" + x.id + ")"));
|
|
4662
4900
|
return {
|
|
4663
4901
|
...sanitizedTools?.reduce(
|
|
4664
|
-
(prev, cur) =>
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
}) => {
|
|
4696
|
-
const mime = getMimeType(type);
|
|
4697
|
-
const prefix = exuluConfig?.fileUploads?.s3prefix ? `${exuluConfig.fileUploads.s3prefix.replace(/\/$/, "")}/` : "";
|
|
4698
|
-
const key = `${prefix}${user}/${generateS3Key(name)}${type}`;
|
|
4699
|
-
const command = new import_client_s32.PutObjectCommand({
|
|
4700
|
-
Bucket: exuluConfig?.fileUploads?.s3Bucket,
|
|
4701
|
-
Key: key,
|
|
4702
|
-
Body: data,
|
|
4703
|
-
ContentType: mime
|
|
4902
|
+
(prev, cur) => {
|
|
4903
|
+
let config = configs?.find((config2) => config2.id === cur.id);
|
|
4904
|
+
const userDefinedConfigDescription = config?.config.find((config2) => config2.name === "description")?.value;
|
|
4905
|
+
const defaultConfigDescription = config?.config.find((config2) => config2.name === "description")?.default;
|
|
4906
|
+
const toolDescription = cur.description;
|
|
4907
|
+
const description = userDefinedConfigDescription || defaultConfigDescription || toolDescription;
|
|
4908
|
+
return {
|
|
4909
|
+
...prev,
|
|
4910
|
+
[cur.name]: {
|
|
4911
|
+
...cur.tool,
|
|
4912
|
+
description,
|
|
4913
|
+
async *execute(inputs, options) {
|
|
4914
|
+
if (!cur.tool?.execute) {
|
|
4915
|
+
console.error("[EXULU] Tool execute function is undefined.", cur.tool);
|
|
4916
|
+
throw new Error("Tool execute function is undefined.");
|
|
4917
|
+
}
|
|
4918
|
+
if (config) {
|
|
4919
|
+
config = await hydrateVariables(config || []);
|
|
4920
|
+
}
|
|
4921
|
+
let upload = void 0;
|
|
4922
|
+
if (exuluConfig?.fileUploads?.s3endpoint && exuluConfig?.fileUploads?.s3key && exuluConfig?.fileUploads?.s3secret && exuluConfig?.fileUploads?.s3Bucket) {
|
|
4923
|
+
s3Client2 ??= new import_client_s32.S3Client({
|
|
4924
|
+
region: exuluConfig?.fileUploads?.s3region,
|
|
4925
|
+
...exuluConfig?.fileUploads?.s3endpoint && {
|
|
4926
|
+
forcePathStyle: true,
|
|
4927
|
+
endpoint: exuluConfig?.fileUploads?.s3endpoint
|
|
4928
|
+
},
|
|
4929
|
+
credentials: {
|
|
4930
|
+
accessKeyId: exuluConfig?.fileUploads?.s3key ?? "",
|
|
4931
|
+
secretAccessKey: exuluConfig?.fileUploads?.s3secret ?? ""
|
|
4932
|
+
}
|
|
4704
4933
|
});
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4934
|
+
upload = async ({
|
|
4935
|
+
name,
|
|
4936
|
+
data,
|
|
4937
|
+
type,
|
|
4938
|
+
tags
|
|
4939
|
+
}) => {
|
|
4940
|
+
const mime = getMimeType(type);
|
|
4941
|
+
const prefix = exuluConfig?.fileUploads?.s3prefix ? `${exuluConfig.fileUploads.s3prefix.replace(/\/$/, "")}/` : "";
|
|
4942
|
+
const key = `${prefix}${user}/${generateS3Key(name)}${type}`;
|
|
4943
|
+
const command = new import_client_s32.PutObjectCommand({
|
|
4944
|
+
Bucket: exuluConfig?.fileUploads?.s3Bucket,
|
|
4945
|
+
Key: key,
|
|
4946
|
+
Body: data,
|
|
4947
|
+
ContentType: mime
|
|
4948
|
+
});
|
|
4949
|
+
try {
|
|
4950
|
+
const response2 = await s3Client2.send(command);
|
|
4951
|
+
console.log(response2);
|
|
4952
|
+
return response2;
|
|
4953
|
+
} catch (caught) {
|
|
4954
|
+
if (caught instanceof import_client_s32.S3ServiceException && caught.name === "EntityTooLarge") {
|
|
4955
|
+
console.error(
|
|
4956
|
+
`[EXULU] Error from S3 while uploading object to ${exuluConfig?.fileUploads?.s3Bucket}. The object was too large. To upload objects larger than 5GB, use the S3 console (160GB max) or the multipart upload API (5TB max).`
|
|
4957
|
+
);
|
|
4958
|
+
} else if (caught instanceof import_client_s32.S3ServiceException) {
|
|
4959
|
+
console.error(
|
|
4960
|
+
`[EXULU] Error from S3 while uploading object to ${exuluConfig?.fileUploads?.s3Bucket}. ${caught.name}: ${caught.message}`
|
|
4961
|
+
);
|
|
4962
|
+
} else {
|
|
4963
|
+
throw caught;
|
|
4964
|
+
}
|
|
4720
4965
|
}
|
|
4721
|
-
}
|
|
4722
|
-
}
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
acc[curr.id] = curr;
|
|
4726
|
-
return acc;
|
|
4727
|
-
}, {});
|
|
4728
|
-
console.log("[EXULU] Config", config);
|
|
4729
|
-
const response = await cur.tool.execute({
|
|
4730
|
-
...inputs,
|
|
4731
|
-
// Convert config to object format if a config object
|
|
4732
|
-
// is available, after we added the .value property
|
|
4733
|
-
// by hydrating it from the variables table.
|
|
4734
|
-
providerapikey,
|
|
4735
|
-
allExuluTools,
|
|
4736
|
-
currentTools,
|
|
4737
|
-
user,
|
|
4738
|
-
contexts: contextsMap,
|
|
4739
|
-
upload,
|
|
4740
|
-
config: config ? config.config.reduce((acc, curr) => {
|
|
4741
|
-
acc[curr.name] = curr.value;
|
|
4966
|
+
};
|
|
4967
|
+
}
|
|
4968
|
+
const contextsMap = contexts?.reduce((acc, curr) => {
|
|
4969
|
+
acc[curr.id] = curr;
|
|
4742
4970
|
return acc;
|
|
4743
|
-
}, {})
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4971
|
+
}, {});
|
|
4972
|
+
console.log("[EXULU] Config", config);
|
|
4973
|
+
const response = await cur.tool.execute({
|
|
4974
|
+
...inputs,
|
|
4975
|
+
sessionID,
|
|
4976
|
+
// Convert config to object format if a config object
|
|
4977
|
+
// is available, after we added the .value property
|
|
4978
|
+
// by hydrating it from the variables table.
|
|
4979
|
+
providerapikey,
|
|
4980
|
+
allExuluTools,
|
|
4981
|
+
currentTools,
|
|
4982
|
+
user,
|
|
4983
|
+
contexts: contextsMap,
|
|
4984
|
+
upload,
|
|
4985
|
+
config: config ? config.config.reduce((acc, curr) => {
|
|
4986
|
+
acc[curr.name] = curr.value;
|
|
4987
|
+
return acc;
|
|
4988
|
+
}, {}) : {}
|
|
4989
|
+
}, options);
|
|
4990
|
+
await updateStatistic({
|
|
4991
|
+
name: "count",
|
|
4992
|
+
label: cur.name,
|
|
4993
|
+
type: STATISTICS_TYPE_ENUM.TOOL_CALL,
|
|
4994
|
+
trigger: "agent",
|
|
4995
|
+
count: 1,
|
|
4996
|
+
user: user?.id,
|
|
4997
|
+
role: user?.role?.id
|
|
4998
|
+
});
|
|
4999
|
+
yield response;
|
|
5000
|
+
return response;
|
|
5001
|
+
}
|
|
4756
5002
|
}
|
|
4757
|
-
}
|
|
4758
|
-
}
|
|
5003
|
+
};
|
|
5004
|
+
},
|
|
4759
5005
|
{}
|
|
4760
5006
|
)
|
|
4761
5007
|
// askForConfirmation
|
|
@@ -4764,6 +5010,9 @@ var convertToolsArrayToObject = (currentTools, allExuluTools, configs, providera
|
|
|
4764
5010
|
var hydrateVariables = async (tool2) => {
|
|
4765
5011
|
const { db: db3 } = await postgresClient();
|
|
4766
5012
|
const promises = tool2.config.map(async (toolConfig) => {
|
|
5013
|
+
if (!toolConfig.variable) {
|
|
5014
|
+
return toolConfig;
|
|
5015
|
+
}
|
|
4767
5016
|
const variableName = toolConfig.variable;
|
|
4768
5017
|
const variable = await db3.from("variables").where({ name: variableName }).first();
|
|
4769
5018
|
if (!variable) {
|
|
@@ -4776,6 +5025,7 @@ var hydrateVariables = async (tool2) => {
|
|
|
4776
5025
|
value = bytes.toString(import_crypto_js2.default.enc.Utf8);
|
|
4777
5026
|
}
|
|
4778
5027
|
toolConfig.value = value;
|
|
5028
|
+
return toolConfig;
|
|
4779
5029
|
});
|
|
4780
5030
|
await Promise.all(promises);
|
|
4781
5031
|
console.log("[EXULU] Variable values retrieved and added to tool config.");
|
|
@@ -5033,7 +5283,8 @@ var ExuluAgent2 = class {
|
|
|
5033
5283
|
providerapikey,
|
|
5034
5284
|
contexts,
|
|
5035
5285
|
user,
|
|
5036
|
-
exuluConfig
|
|
5286
|
+
exuluConfig,
|
|
5287
|
+
session
|
|
5037
5288
|
),
|
|
5038
5289
|
stopWhen: [(0, import_ai.stepCountIs)(2)]
|
|
5039
5290
|
});
|
|
@@ -5091,7 +5342,8 @@ var ExuluAgent2 = class {
|
|
|
5091
5342
|
providerapikey,
|
|
5092
5343
|
contexts,
|
|
5093
5344
|
user,
|
|
5094
|
-
exuluConfig
|
|
5345
|
+
exuluConfig,
|
|
5346
|
+
session
|
|
5095
5347
|
),
|
|
5096
5348
|
stopWhen: [(0, import_ai.stepCountIs)(2)]
|
|
5097
5349
|
});
|
|
@@ -5204,7 +5456,8 @@ var ExuluAgent2 = class {
|
|
|
5204
5456
|
providerapikey,
|
|
5205
5457
|
contexts,
|
|
5206
5458
|
user,
|
|
5207
|
-
exuluConfig
|
|
5459
|
+
exuluConfig,
|
|
5460
|
+
session
|
|
5208
5461
|
),
|
|
5209
5462
|
onError: (error) => {
|
|
5210
5463
|
console.error("[EXULU] chat stream error.", error);
|
|
@@ -5229,6 +5482,15 @@ var getAgentMessages = async ({ session, user, limit, page }) => {
|
|
|
5229
5482
|
const messages = await query;
|
|
5230
5483
|
return messages;
|
|
5231
5484
|
};
|
|
5485
|
+
var getSession = async ({ sessionID }) => {
|
|
5486
|
+
const { db: db3 } = await postgresClient();
|
|
5487
|
+
console.log("[EXULU] getting session for session ID: " + sessionID);
|
|
5488
|
+
const session = await db3.from("agent_sessions").where({ id: sessionID }).first();
|
|
5489
|
+
if (!session) {
|
|
5490
|
+
throw new Error("Session not found for session ID: " + sessionID);
|
|
5491
|
+
}
|
|
5492
|
+
return session;
|
|
5493
|
+
};
|
|
5232
5494
|
var saveChat = async ({ session, user, messages }) => {
|
|
5233
5495
|
const { db: db3 } = await postgresClient();
|
|
5234
5496
|
const promises = messages.map((message) => {
|
|
@@ -5516,6 +5778,9 @@ var ExuluContext = class {
|
|
|
5516
5778
|
};
|
|
5517
5779
|
};
|
|
5518
5780
|
createItem = async (item, config, user, role, upsert) => {
|
|
5781
|
+
if (upsert && (!item.id && !item.external_id)) {
|
|
5782
|
+
throw new Error("Item id or external id is required for upsert.");
|
|
5783
|
+
}
|
|
5519
5784
|
const { db: db3 } = await postgresClient();
|
|
5520
5785
|
const mutation = db3.from(getTableName(
|
|
5521
5786
|
this.id
|
|
@@ -5943,6 +6208,8 @@ var {
|
|
|
5943
6208
|
variablesSchema: variablesSchema2,
|
|
5944
6209
|
workflowTemplatesSchema: workflowTemplatesSchema2,
|
|
5945
6210
|
rbacSchema: rbacSchema2,
|
|
6211
|
+
promptLibrarySchema: promptLibrarySchema2,
|
|
6212
|
+
promptFavoritesSchema: promptFavoritesSchema2,
|
|
5946
6213
|
statisticsSchema: statisticsSchema2
|
|
5947
6214
|
} = coreSchemas.get();
|
|
5948
6215
|
var createExpressRoutes = async (app, agents, tools, contexts, config, evals, tracer, queues2) => {
|
|
@@ -5973,6 +6240,8 @@ var createExpressRoutes = async (app, agents, tools, contexts, config, evals, tr
|
|
|
5973
6240
|
agentsSchema2(),
|
|
5974
6241
|
projectsSchema2(),
|
|
5975
6242
|
jobResultsSchema2(),
|
|
6243
|
+
promptLibrarySchema2(),
|
|
6244
|
+
promptFavoritesSchema2(),
|
|
5976
6245
|
evalRunsSchema2(),
|
|
5977
6246
|
platformConfigurationsSchema2(),
|
|
5978
6247
|
evalSetsSchema2(),
|
|
@@ -5996,25 +6265,13 @@ var createExpressRoutes = async (app, agents, tools, contexts, config, evals, tr
|
|
|
5996
6265
|
import_express3.default.json({ limit: REQUEST_SIZE_LIMIT }),
|
|
5997
6266
|
(0, import_express5.expressMiddleware)(server, {
|
|
5998
6267
|
context: async ({ req }) => {
|
|
5999
|
-
console.info("[EXULU] Incoming graphql request", {
|
|
6000
|
-
message: "Incoming Request",
|
|
6001
|
-
method: req.method,
|
|
6002
|
-
path: req.path,
|
|
6003
|
-
requestId: "req-" + Date.now(),
|
|
6004
|
-
ipAddress: req.ip,
|
|
6005
|
-
userAgent: req.get("User-Agent"),
|
|
6006
|
-
headers: {
|
|
6007
|
-
"authorization": req.headers["authorization"],
|
|
6008
|
-
"exulu-api-key": req.headers["exulu-api-key"],
|
|
6009
|
-
"origin": req.headers["origin"],
|
|
6010
|
-
"...": "..."
|
|
6011
|
-
}
|
|
6012
|
-
});
|
|
6013
6268
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
6014
6269
|
if (!authenticationResult.user?.id) {
|
|
6270
|
+
console.error("[EXULU] Authentication failed", authenticationResult);
|
|
6015
6271
|
throw new Error(authenticationResult.message);
|
|
6016
6272
|
}
|
|
6017
6273
|
const { db: db3 } = await postgresClient();
|
|
6274
|
+
console.log("[EXULU] Graphql call");
|
|
6018
6275
|
return {
|
|
6019
6276
|
req,
|
|
6020
6277
|
db: db3,
|
|
@@ -6628,7 +6885,7 @@ var import_ai3 = require("ai");
|
|
|
6628
6885
|
var import_crypto_js4 = __toESM(require("crypto-js"), 1);
|
|
6629
6886
|
|
|
6630
6887
|
// src/registry/log-metadata.ts
|
|
6631
|
-
function
|
|
6888
|
+
function logMetadata2(id, additionalMetadata) {
|
|
6632
6889
|
return {
|
|
6633
6890
|
__logMetadata: true,
|
|
6634
6891
|
id,
|
|
@@ -6639,16 +6896,6 @@ function logMetadata(id, additionalMetadata) {
|
|
|
6639
6896
|
// src/registry/workers.ts
|
|
6640
6897
|
var redisConnection;
|
|
6641
6898
|
var createWorkers = async (agents, queues2, config, contexts, evals, tools, tracer) => {
|
|
6642
|
-
console.log(`
|
|
6643
|
-
\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
|
|
6644
|
-
\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
|
|
6645
|
-
\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
|
|
6646
|
-
\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
|
|
6647
|
-
\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
|
|
6648
|
-
\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
|
|
6649
|
-
Intelligence Management Platform - Workers
|
|
6650
|
-
|
|
6651
|
-
`);
|
|
6652
6899
|
console.log("[EXULU] creating workers for " + queues2?.length + " queues.");
|
|
6653
6900
|
console.log("[EXULU] queues", queues2.map((q) => q.queue.name));
|
|
6654
6901
|
if (!redisServer.host || !redisServer.port) {
|
|
@@ -6675,7 +6922,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6675
6922
|
const worker = new import_bullmq4.Worker(
|
|
6676
6923
|
`${queue.queue.name}`,
|
|
6677
6924
|
async (bullmqJob) => {
|
|
6678
|
-
console.log("[EXULU] starting execution for job",
|
|
6925
|
+
console.log("[EXULU] starting execution for job", logMetadata2(bullmqJob.name, {
|
|
6679
6926
|
name: bullmqJob.name,
|
|
6680
6927
|
status: await bullmqJob.getState(),
|
|
6681
6928
|
type: bullmqJob.data.type
|
|
@@ -6692,7 +6939,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6692
6939
|
try {
|
|
6693
6940
|
bullmq.validate(bullmqJob.id, data);
|
|
6694
6941
|
if (data.type === "embedder") {
|
|
6695
|
-
console.log("[EXULU] running an embedder job.",
|
|
6942
|
+
console.log("[EXULU] running an embedder job.", logMetadata2(bullmqJob.name));
|
|
6696
6943
|
const label = `embedder-${bullmqJob.name}`;
|
|
6697
6944
|
await db3.from("job_results").insert({
|
|
6698
6945
|
job_id: bullmqJob.id,
|
|
@@ -6722,7 +6969,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6722
6969
|
};
|
|
6723
6970
|
}
|
|
6724
6971
|
if (data.type === "processor") {
|
|
6725
|
-
console.log("[EXULU] running a processor job.",
|
|
6972
|
+
console.log("[EXULU] running a processor job.", logMetadata2(bullmqJob.name));
|
|
6726
6973
|
const label = `processor-${bullmqJob.name}`;
|
|
6727
6974
|
await db3.from("job_results").insert({
|
|
6728
6975
|
job_id: bullmqJob.id,
|
|
@@ -6769,10 +7016,11 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6769
7016
|
};
|
|
6770
7017
|
}
|
|
6771
7018
|
if (data.type === "eval_run") {
|
|
6772
|
-
console.log("[EXULU] running an eval run job.",
|
|
7019
|
+
console.log("[EXULU] running an eval run job.", logMetadata2(bullmqJob.name));
|
|
6773
7020
|
const label = `eval-run-${data.eval_run_id}-${data.test_case_id}`;
|
|
6774
7021
|
const existingResult = await db3.from("job_results").where({ label }).first();
|
|
6775
7022
|
if (existingResult) {
|
|
7023
|
+
console.log("[EXULU] found existing job result, so ");
|
|
6776
7024
|
await db3.from("job_results").where({ label }).update({
|
|
6777
7025
|
job_id: bullmqJob.id,
|
|
6778
7026
|
label,
|
|
@@ -6817,7 +7065,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6817
7065
|
resolve(messages2);
|
|
6818
7066
|
break;
|
|
6819
7067
|
} catch (error) {
|
|
6820
|
-
console.error(`[EXULU] error processing UI messages flow for agent ${agentInstance.name} (${agentInstance.id}).`,
|
|
7068
|
+
console.error(`[EXULU] error processing UI messages flow for agent ${agentInstance.name} (${agentInstance.id}).`, logMetadata2(bullmqJob.name, {
|
|
6821
7069
|
error: error instanceof Error ? error.message : String(error)
|
|
6822
7070
|
}));
|
|
6823
7071
|
attempts++;
|
|
@@ -6874,9 +7122,11 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6874
7122
|
test_case_id: testCase.id,
|
|
6875
7123
|
eval_run_id: evalRun.id,
|
|
6876
7124
|
eval_function_id: evalFunction.id,
|
|
7125
|
+
eval_function_name: evalFunction.name,
|
|
7126
|
+
eval_function_config: evalFunction.config || {},
|
|
6877
7127
|
result: result2 || 0
|
|
6878
7128
|
};
|
|
6879
|
-
console.log(`[EXULU] eval function ${evalFunction.id} result: ${result2}`,
|
|
7129
|
+
console.log(`[EXULU] eval function ${evalFunction.id} result: ${result2}`, logMetadata2(bullmqJob.name, {
|
|
6880
7130
|
result: result2 || 0
|
|
6881
7131
|
}));
|
|
6882
7132
|
evalFunctionResults.push(evalFunctionResult);
|
|
@@ -6895,34 +7145,44 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6895
7145
|
result: result2 || 0
|
|
6896
7146
|
};
|
|
6897
7147
|
evalFunctionResults.push(evalFunctionResult);
|
|
6898
|
-
console.log(`[EXULU] eval function ${evalFunction.id} result: ${result2}`,
|
|
7148
|
+
console.log(`[EXULU] eval function ${evalFunction.id} result: ${result2}`, logMetadata2(bullmqJob.name, {
|
|
6899
7149
|
result: result2 || 0
|
|
6900
7150
|
}));
|
|
6901
7151
|
}
|
|
6902
7152
|
}
|
|
6903
7153
|
const scores = evalFunctionResults.map((result2) => result2.result);
|
|
7154
|
+
console.log("[EXULU] Exulu eval run scores for test case: " + testCase.id, scores);
|
|
6904
7155
|
let score = 0;
|
|
6905
|
-
switch (data.scoring_method) {
|
|
7156
|
+
switch (data.scoring_method?.toLowerCase()) {
|
|
6906
7157
|
case "median":
|
|
7158
|
+
console.log("[EXULU] Calculating median score");
|
|
6907
7159
|
score = getMedian(scores);
|
|
6908
7160
|
break;
|
|
6909
7161
|
case "average":
|
|
7162
|
+
console.log("[EXULU] Calculating average score");
|
|
6910
7163
|
score = getAverage(scores);
|
|
6911
7164
|
break;
|
|
6912
7165
|
case "sum":
|
|
7166
|
+
console.log("[EXULU] Calculating sum score");
|
|
6913
7167
|
score = getSum(scores);
|
|
6914
7168
|
break;
|
|
7169
|
+
default:
|
|
7170
|
+
console.log("[EXULU] Calculating average score");
|
|
7171
|
+
score = getAverage(scores);
|
|
6915
7172
|
}
|
|
6916
7173
|
return {
|
|
6917
7174
|
result: score,
|
|
6918
7175
|
metadata: {
|
|
6919
|
-
|
|
7176
|
+
messages,
|
|
7177
|
+
function_results: [
|
|
7178
|
+
...evalFunctionResults
|
|
7179
|
+
],
|
|
6920
7180
|
...metadata
|
|
6921
7181
|
}
|
|
6922
7182
|
};
|
|
6923
7183
|
}
|
|
6924
7184
|
if (data.type === "eval_function") {
|
|
6925
|
-
console.log("[EXULU] running an eval function job.",
|
|
7185
|
+
console.log("[EXULU] running an eval function job.", logMetadata2(bullmqJob.name));
|
|
6926
7186
|
if (data.eval_functions?.length !== 1) {
|
|
6927
7187
|
throw new Error(`Expected 1 eval function for eval function job, got ${data.eval_functions?.length}.`);
|
|
6928
7188
|
}
|
|
@@ -6968,7 +7228,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6968
7228
|
inputMessages,
|
|
6969
7229
|
evalFunction.config || {}
|
|
6970
7230
|
);
|
|
6971
|
-
console.log(`[EXULU] eval function ${evalFunction.id} result: ${result}`,
|
|
7231
|
+
console.log(`[EXULU] eval function ${evalFunction.id} result: ${result}`, logMetadata2(bullmqJob.name, {
|
|
6972
7232
|
result: result || 0
|
|
6973
7233
|
}));
|
|
6974
7234
|
}
|
|
@@ -6978,7 +7238,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6978
7238
|
};
|
|
6979
7239
|
}
|
|
6980
7240
|
if (data.type === "source") {
|
|
6981
|
-
console.log("[EXULU] running a source job.",
|
|
7241
|
+
console.log("[EXULU] running a source job.", logMetadata2(bullmqJob.name));
|
|
6982
7242
|
if (!data.source) {
|
|
6983
7243
|
throw new Error(`No source id set for source job.`);
|
|
6984
7244
|
}
|
|
@@ -7000,18 +7260,27 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7000
7260
|
const { item: createdItem, job } = await context.createItem(item, config, data.user, data.role);
|
|
7001
7261
|
if (job) {
|
|
7002
7262
|
jobs.push(job);
|
|
7003
|
-
console.log(`[EXULU] Scheduled job through source update job for item ${createdItem.id} (Job ID: ${job})`,
|
|
7263
|
+
console.log(`[EXULU] Scheduled job through source update job for item ${createdItem.id} (Job ID: ${job})`, logMetadata2(bullmqJob.name, {
|
|
7004
7264
|
item: createdItem,
|
|
7005
7265
|
job
|
|
7006
7266
|
}));
|
|
7007
7267
|
}
|
|
7008
7268
|
if (createdItem.id) {
|
|
7009
7269
|
items.push(createdItem.id);
|
|
7010
|
-
console.log(`[EXULU] created item through source update job ${createdItem.id}`,
|
|
7270
|
+
console.log(`[EXULU] created item through source update job ${createdItem.id}`, logMetadata2(bullmqJob.name, {
|
|
7011
7271
|
item: createdItem
|
|
7012
7272
|
}));
|
|
7013
7273
|
}
|
|
7014
7274
|
}
|
|
7275
|
+
await updateStatistic({
|
|
7276
|
+
name: "count",
|
|
7277
|
+
label: source.id,
|
|
7278
|
+
type: STATISTICS_TYPE_ENUM.SOURCE_UPDATE,
|
|
7279
|
+
trigger: "api",
|
|
7280
|
+
count: 1,
|
|
7281
|
+
user: data?.user,
|
|
7282
|
+
role: data?.role
|
|
7283
|
+
});
|
|
7015
7284
|
return {
|
|
7016
7285
|
result,
|
|
7017
7286
|
metadata: {
|
|
@@ -7042,7 +7311,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7042
7311
|
}
|
|
7043
7312
|
);
|
|
7044
7313
|
worker.on("completed", async (job, returnvalue) => {
|
|
7045
|
-
console.log(`[EXULU] completed job ${job.id}.`,
|
|
7314
|
+
console.log(`[EXULU] completed job ${job.id}.`, logMetadata2(job.name, {
|
|
7046
7315
|
result: returnvalue
|
|
7047
7316
|
}));
|
|
7048
7317
|
const { db: db3 } = await postgresClient();
|
|
@@ -7062,7 +7331,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7062
7331
|
});
|
|
7063
7332
|
return;
|
|
7064
7333
|
}
|
|
7065
|
-
console.error(`[EXULU] job failed.`, job?.name ?
|
|
7334
|
+
console.error(`[EXULU] job failed.`, job?.name ? logMetadata2(job.name, {
|
|
7066
7335
|
error: error instanceof Error ? error.message : String(error)
|
|
7067
7336
|
}) : error);
|
|
7068
7337
|
});
|
|
@@ -7070,7 +7339,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7070
7339
|
console.error(`[EXULU] worker error.`, error);
|
|
7071
7340
|
});
|
|
7072
7341
|
worker.on("progress", (job, progress) => {
|
|
7073
|
-
console.log(`[EXULU] job progress ${job.id}.`,
|
|
7342
|
+
console.log(`[EXULU] job progress ${job.id}.`, logMetadata2(job.name, {
|
|
7074
7343
|
progress
|
|
7075
7344
|
}));
|
|
7076
7345
|
});
|
|
@@ -7449,6 +7718,92 @@ var ExuluMCP = class {
|
|
|
7449
7718
|
});
|
|
7450
7719
|
server.tools[tool2.id] = tool2.name;
|
|
7451
7720
|
}
|
|
7721
|
+
const getListOfPromptTemplatesName = "getListOfPromptTemplates";
|
|
7722
|
+
if (!server.tools[getListOfPromptTemplatesName]) {
|
|
7723
|
+
server.mcp.registerTool(getListOfPromptTemplatesName, {
|
|
7724
|
+
title: "Get List of Prompt Templates",
|
|
7725
|
+
description: "Retrieves a list of prompt templates available for this agent. Returns the name, description, and ID of each template.",
|
|
7726
|
+
inputSchema: {
|
|
7727
|
+
inputs: import_zod2.z.object({})
|
|
7728
|
+
}
|
|
7729
|
+
}, async ({ inputs }, args) => {
|
|
7730
|
+
console.log("[EXULU] Getting list of prompt templates for agent", agentInstance.id);
|
|
7731
|
+
const { db: db4 } = await postgresClient();
|
|
7732
|
+
const prompts = await db4.from("prompt_library").select("id", "name", "description").whereRaw("assigned_agents @> ?::jsonb", [JSON.stringify(agentInstance.id)]).orderBy("updatedAt", "desc");
|
|
7733
|
+
console.log("[EXULU] Found", prompts.length, "prompt templates");
|
|
7734
|
+
return {
|
|
7735
|
+
content: [{
|
|
7736
|
+
type: "text",
|
|
7737
|
+
text: JSON.stringify({
|
|
7738
|
+
prompts: prompts.map((p) => ({
|
|
7739
|
+
id: p.id,
|
|
7740
|
+
name: p.name,
|
|
7741
|
+
description: p.description || "No description provided"
|
|
7742
|
+
})),
|
|
7743
|
+
count: prompts.length
|
|
7744
|
+
}, null, 2)
|
|
7745
|
+
}],
|
|
7746
|
+
structuredContent: {
|
|
7747
|
+
prompts: prompts.map((p) => ({
|
|
7748
|
+
id: p.id,
|
|
7749
|
+
name: p.name,
|
|
7750
|
+
description: p.description || "No description provided"
|
|
7751
|
+
})),
|
|
7752
|
+
count: prompts.length
|
|
7753
|
+
}
|
|
7754
|
+
};
|
|
7755
|
+
});
|
|
7756
|
+
}
|
|
7757
|
+
const getPromptTemplateDetailsName = "getPromptTemplateDetails";
|
|
7758
|
+
if (!server.tools[getPromptTemplateDetailsName]) {
|
|
7759
|
+
server.mcp.registerTool(getPromptTemplateDetailsName, {
|
|
7760
|
+
title: "Get Prompt Template Details",
|
|
7761
|
+
description: "Retrieves the full details of a specific prompt template by ID, including the actual template content with variables.",
|
|
7762
|
+
inputSchema: {
|
|
7763
|
+
inputs: import_zod2.z.object({
|
|
7764
|
+
id: import_zod2.z.string().describe("The ID of the prompt template to retrieve")
|
|
7765
|
+
})
|
|
7766
|
+
}
|
|
7767
|
+
}, async ({ inputs }, args) => {
|
|
7768
|
+
console.log("[EXULU] Getting prompt template details for ID", inputs.id);
|
|
7769
|
+
const { db: db4 } = await postgresClient();
|
|
7770
|
+
const prompt = await db4.from("prompt_library").select("id", "name", "description", "content", "createdAt", "updatedAt", "usage_count", "favorite_count").where({ id: inputs.id }).first();
|
|
7771
|
+
if (!prompt) {
|
|
7772
|
+
throw new Error(`Prompt template with ID ${inputs.id} not found`);
|
|
7773
|
+
}
|
|
7774
|
+
const isAssignedToAgent = await db4.from("prompt_library").select("id").where({ id: inputs.id }).whereRaw("assigned_agents @> ?::jsonb", [JSON.stringify(agentInstance.id)]).first();
|
|
7775
|
+
console.log("[EXULU] Prompt template found:", prompt.name);
|
|
7776
|
+
return {
|
|
7777
|
+
content: [{
|
|
7778
|
+
type: "text",
|
|
7779
|
+
text: JSON.stringify({
|
|
7780
|
+
id: prompt.id,
|
|
7781
|
+
name: prompt.name,
|
|
7782
|
+
description: prompt.description || "No description provided",
|
|
7783
|
+
content: prompt.content,
|
|
7784
|
+
createdAt: prompt.createdAt,
|
|
7785
|
+
updatedAt: prompt.updatedAt,
|
|
7786
|
+
usageCount: prompt.usage_count || 0,
|
|
7787
|
+
favoriteCount: prompt.favorite_count || 0,
|
|
7788
|
+
isAssignedToThisAgent: !!isAssignedToAgent
|
|
7789
|
+
}, null, 2)
|
|
7790
|
+
}],
|
|
7791
|
+
structuredContent: {
|
|
7792
|
+
id: prompt.id,
|
|
7793
|
+
name: prompt.name,
|
|
7794
|
+
description: prompt.description || "No description provided",
|
|
7795
|
+
content: prompt.content,
|
|
7796
|
+
createdAt: prompt.createdAt,
|
|
7797
|
+
updatedAt: prompt.updatedAt,
|
|
7798
|
+
usageCount: prompt.usage_count || 0,
|
|
7799
|
+
favoriteCount: prompt.favorite_count || 0,
|
|
7800
|
+
isAssignedToThisAgent: !!isAssignedToAgent
|
|
7801
|
+
}
|
|
7802
|
+
};
|
|
7803
|
+
});
|
|
7804
|
+
}
|
|
7805
|
+
server.tools[getListOfPromptTemplatesName] = getListOfPromptTemplatesName;
|
|
7806
|
+
server.tools[getPromptTemplateDetailsName] = getPromptTemplateDetailsName;
|
|
7452
7807
|
return server.mcp;
|
|
7453
7808
|
};
|
|
7454
7809
|
create = async ({ express: express3, allTools, allAgents, allContexts, config }) => {
|
|
@@ -8063,8 +8418,8 @@ var llmAsJudgeEval = () => {
|
|
|
8063
8418
|
console.log("[EXULU] running llm as judge eval", { agent, backend, messages, testCase, config });
|
|
8064
8419
|
let prompt = config?.prompt;
|
|
8065
8420
|
if (!prompt) {
|
|
8066
|
-
console.error("[EXULU] prompt is required.");
|
|
8067
|
-
throw new Error("Prompt is required.");
|
|
8421
|
+
console.error("[EXULU] prompt is required for llm as judge eval but none is provided.");
|
|
8422
|
+
throw new Error("Prompt is required for llm as judge eval but none is provided.");
|
|
8068
8423
|
}
|
|
8069
8424
|
const lastMessage = messages[messages.length - 1]?.parts?.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
8070
8425
|
console.log("[EXULU] last message", lastMessage);
|
|
@@ -8722,6 +9077,280 @@ var mathTools = [
|
|
|
8722
9077
|
degreesToRadiansTool
|
|
8723
9078
|
];
|
|
8724
9079
|
|
|
9080
|
+
// src/templates/tools/todo/todowrite.txt
|
|
9081
|
+
var todowrite_default = `Use this tool to create and manage a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
|
|
9082
|
+
It also helps the user understand the progress of the task and overall progress of their requests.
|
|
9083
|
+
|
|
9084
|
+
## When to Use This Tool
|
|
9085
|
+
Use this tool proactively in these scenarios:
|
|
9086
|
+
|
|
9087
|
+
1. Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
|
|
9088
|
+
2. Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
|
|
9089
|
+
3. User explicitly requests todo list - When the user directly asks you to use the todo list
|
|
9090
|
+
4. User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
|
|
9091
|
+
5. After receiving new instructions - Immediately capture user requirements as todos. Feel free to edit the todo list based on new information.
|
|
9092
|
+
6. After completing a task - Mark it complete and add any new follow-up tasks
|
|
9093
|
+
7. When you start working on a new task, mark the todo as in_progress. Ideally you should only have one todo as in_progress at a time. Complete existing tasks before starting new ones.
|
|
9094
|
+
|
|
9095
|
+
## When NOT to Use This Tool
|
|
9096
|
+
|
|
9097
|
+
Skip using this tool when:
|
|
9098
|
+
1. There is only a single, straightforward task
|
|
9099
|
+
2. The task is trivial and tracking it provides no organizational benefit
|
|
9100
|
+
3. The task can be completed in less than 3 trivial steps
|
|
9101
|
+
4. The task is purely conversational or informational
|
|
9102
|
+
|
|
9103
|
+
NOTE that you should not use this tool if there is only one trivial task to do. In this case you are better off just doing the task directly.
|
|
9104
|
+
|
|
9105
|
+
## Examples of When to Use the Todo List
|
|
9106
|
+
|
|
9107
|
+
<example>
|
|
9108
|
+
User: I want to add a dark mode toggle to the application settings. Make sure you run the tests and build when you're done!
|
|
9109
|
+
Assistant: I'll help add a dark mode toggle to your application settings. Let me create a todo list to track this implementation.
|
|
9110
|
+
*Creates todo list with the following items:*
|
|
9111
|
+
1. Create dark mode toggle component in Settings page
|
|
9112
|
+
2. Add dark mode state management (context/store)
|
|
9113
|
+
3. Implement CSS-in-JS styles for dark theme
|
|
9114
|
+
4. Update existing components to support theme switching
|
|
9115
|
+
5. Run tests and build process, addressing any failures or errors that occur
|
|
9116
|
+
*Begins working on the first task*
|
|
9117
|
+
|
|
9118
|
+
<reasoning>
|
|
9119
|
+
The assistant used the todo list because:
|
|
9120
|
+
1. Adding dark mode is a multi-step feature requiring UI, state management, and styling changes
|
|
9121
|
+
2. The user explicitly requested tests and build be run afterward
|
|
9122
|
+
3. The assistant inferred that tests and build need to pass by adding "Ensure tests and build succeed" as the final task
|
|
9123
|
+
</reasoning>
|
|
9124
|
+
</example>
|
|
9125
|
+
|
|
9126
|
+
<example>
|
|
9127
|
+
User: Help me rename the function getCwd to getCurrentWorkingDirectory across my project
|
|
9128
|
+
Assistant: Let me first search through your codebase to find all occurrences of 'getCwd'.
|
|
9129
|
+
*Uses grep or search tools to locate all instances of getCwd in the codebase*
|
|
9130
|
+
Assistant: I've found 15 instances of 'getCwd' across 8 different files. Let me create a todo list to track these changes.
|
|
9131
|
+
*Creates todo list with specific items for each file that needs updating*
|
|
9132
|
+
|
|
9133
|
+
<reasoning>
|
|
9134
|
+
The assistant used the todo list because:
|
|
9135
|
+
1. First, the assistant searched to understand the scope of the task
|
|
9136
|
+
2. Upon finding multiple occurrences across different files, it determined this was a complex task with multiple steps
|
|
9137
|
+
3. The todo list helps ensure every instance is tracked and updated systematically
|
|
9138
|
+
4. This approach prevents missing any occurrences and maintains code consistency
|
|
9139
|
+
</reasoning>
|
|
9140
|
+
</example>
|
|
9141
|
+
|
|
9142
|
+
|
|
9143
|
+
<example>
|
|
9144
|
+
User: I need to implement these features for my e-commerce site: user registration, product catalog, shopping cart, and checkout flow.
|
|
9145
|
+
Assistant: I'll help implement these features. First, let's add all the features to the todo list.
|
|
9146
|
+
*Creates a todo list breaking down each feature into specific tasks based on the project architecture*
|
|
9147
|
+
Assistant: Let's start with user registration. This will involve creating database models, API endpoints, and frontend forms that integrate with your existing authentication system.
|
|
9148
|
+
|
|
9149
|
+
<reasoning>
|
|
9150
|
+
The assistant used the todo list because:
|
|
9151
|
+
1. The user provided multiple complex features to implement in a comma separated list
|
|
9152
|
+
2. The todo list helps organize these large features into manageable tasks
|
|
9153
|
+
3. This approach allows for tracking progress across the entire implementation
|
|
9154
|
+
</reasoning>
|
|
9155
|
+
</example>
|
|
9156
|
+
|
|
9157
|
+
<example>
|
|
9158
|
+
User: Can you help optimize my React application? It's rendering slowly and has performance issues.</user>
|
|
9159
|
+
Assistant: I'll help optimize your React application. First, let me examine your codebase to identify potential performance bottlenecks.
|
|
9160
|
+
*Reviews component structure, render patterns, state management, and data fetching*
|
|
9161
|
+
Assistant: After analyzing your codebase, I've identified several performance issues. Let me create a todo list to track our optimization efforts.
|
|
9162
|
+
*Creates todo list with items like: 1) Implement memoization for expensive calculations in ProductList, 2) Add virtualization for long lists in Dashboard, 3) Optimize image loading in Gallery component, 4) Fix state update loops in ShoppingCart, 5) Review bundle size and implement code splitting*
|
|
9163
|
+
Let's start by implementing memoization for the expensive calculations in your ProductList component.</assistant>
|
|
9164
|
+
|
|
9165
|
+
<reasoning>
|
|
9166
|
+
The assistant used the todo list because:
|
|
9167
|
+
1. First, the assistant examined the codebase to identify specific performance issues
|
|
9168
|
+
2. Based on this analysis, it identified multiple optimization opportunities
|
|
9169
|
+
3. Performance optimization is a non-trivial task requiring multiple steps
|
|
9170
|
+
4. The todo list helps methodically track improvements across different components
|
|
9171
|
+
5. This systematic approach ensures all performance bottlenecks are addressed
|
|
9172
|
+
</reasoning>
|
|
9173
|
+
</example>
|
|
9174
|
+
|
|
9175
|
+
## Examples of When NOT to Use the Todo List
|
|
9176
|
+
|
|
9177
|
+
<example>
|
|
9178
|
+
User: How do I print 'Hello World' in Python?
|
|
9179
|
+
Assistant: In Python, you can print "Hello World" with this simple code:
|
|
9180
|
+
|
|
9181
|
+
python
|
|
9182
|
+
print("Hello World")
|
|
9183
|
+
|
|
9184
|
+
This will output the text "Hello World" to the console when executed.</assistant>
|
|
9185
|
+
|
|
9186
|
+
<reasoning>
|
|
9187
|
+
The assistant did not use the todo list because this is a single, trivial task that can be completed in one step. There's no need to track multiple tasks or steps for such a straightforward request.
|
|
9188
|
+
</reasoning>
|
|
9189
|
+
</example>
|
|
9190
|
+
|
|
9191
|
+
<example>
|
|
9192
|
+
User: What does the git status command do?
|
|
9193
|
+
Assistant: The git status command shows the current state of your working directory and staging area. It displays which changes have been staged, which haven't, and which files aren't being tracked by Git. This is a fundamental command for understanding the current state of your repository before making commits.
|
|
9194
|
+
|
|
9195
|
+
<reasoning>
|
|
9196
|
+
The assistant did not use the todo list because this is an informational request with no actual coding task to complete. The user is simply asking for an explanation, not for the assistant to perform multiple steps or tasks.
|
|
9197
|
+
</reasoning>
|
|
9198
|
+
</example>
|
|
9199
|
+
|
|
9200
|
+
<example>
|
|
9201
|
+
User: Can you add a comment to the calculateTotal function to explain what it does?
|
|
9202
|
+
Assistant: Sure, let me add a comment to the calculateTotal function to explain what it does.
|
|
9203
|
+
* Uses the Edit tool to add a comment to the calculateTotal function *
|
|
9204
|
+
|
|
9205
|
+
<reasoning>
|
|
9206
|
+
The assistant did not use the todo list because this is a single, straightforward task confined to one location in the code. Adding a comment doesn't require tracking multiple steps or systematic organization.
|
|
9207
|
+
</reasoning>
|
|
9208
|
+
</example>
|
|
9209
|
+
|
|
9210
|
+
<example>
|
|
9211
|
+
User: Run npm install for me and tell me what happens.
|
|
9212
|
+
Assistant: I'll run the npm install command for you.
|
|
9213
|
+
|
|
9214
|
+
*Executes: npm install*
|
|
9215
|
+
|
|
9216
|
+
The command completed successfully. Here's the output:
|
|
9217
|
+
[Output of npm install command]
|
|
9218
|
+
|
|
9219
|
+
All dependencies have been installed according to your package.json file.
|
|
9220
|
+
|
|
9221
|
+
<reasoning>
|
|
9222
|
+
The assistant did not use the todo list because this is a single command execution with immediate results. There are no multiple steps to track or organize, making the todo list unnecessary for this straightforward task.
|
|
9223
|
+
</reasoning>
|
|
9224
|
+
</example>
|
|
9225
|
+
|
|
9226
|
+
## Task States and Management
|
|
9227
|
+
|
|
9228
|
+
1. **Task States**: Use these states to track progress:
|
|
9229
|
+
- pending: Task not yet started
|
|
9230
|
+
- in_progress: Currently working on (limit to ONE task at a time)
|
|
9231
|
+
- completed: Task finished successfully
|
|
9232
|
+
- cancelled: Task no longer needed
|
|
9233
|
+
|
|
9234
|
+
2. **Task Management**:
|
|
9235
|
+
- Update task status in real-time as you work
|
|
9236
|
+
- Mark tasks complete IMMEDIATELY after finishing (don't batch completions)
|
|
9237
|
+
- Only have ONE task in_progress at any time
|
|
9238
|
+
- Complete current tasks before starting new ones
|
|
9239
|
+
- Cancel tasks that become irrelevant
|
|
9240
|
+
|
|
9241
|
+
3. **Task Breakdown**:
|
|
9242
|
+
- Create specific, actionable items
|
|
9243
|
+
- Break complex tasks into smaller, manageable steps
|
|
9244
|
+
- Use clear, descriptive task names
|
|
9245
|
+
|
|
9246
|
+
When in doubt, use this tool. Being proactive with task management demonstrates attentiveness and ensures you complete all requirements successfully.
|
|
9247
|
+
`;
|
|
9248
|
+
|
|
9249
|
+
// src/templates/tools/todo/todoread.txt
|
|
9250
|
+
var todoread_default = `Use this tool to read the current to-do list for the session. This tool should be used proactively and frequently to ensure that you are aware of
|
|
9251
|
+
the status of the current task list. You should make use of this tool as often as possible, especially in the following situations:
|
|
9252
|
+
- At the beginning of conversations to see what's pending
|
|
9253
|
+
- Before starting new tasks to prioritize work
|
|
9254
|
+
- When the user asks about previous tasks or plans
|
|
9255
|
+
- Whenever you're uncertain about what to do next
|
|
9256
|
+
- After completing tasks to update your understanding of remaining work
|
|
9257
|
+
- After every few messages to ensure you're on track
|
|
9258
|
+
|
|
9259
|
+
Usage:
|
|
9260
|
+
- This tool takes in no parameters. So leave the input blank or empty. DO NOT include a dummy object, placeholder string or a key like "input" or "empty". LEAVE IT BLANK.
|
|
9261
|
+
- Returns a list of todo items with their status, priority, and content
|
|
9262
|
+
- Use this information to track progress and plan next steps
|
|
9263
|
+
- If no todos exist yet, an empty list will be returned`;
|
|
9264
|
+
|
|
9265
|
+
// src/templates/tools/todo/todo.ts
|
|
9266
|
+
var import_zod5 = __toESM(require("zod"), 1);
|
|
9267
|
+
var TodoSchema = import_zod5.default.object({
|
|
9268
|
+
content: import_zod5.default.string().describe("Brief description of the task"),
|
|
9269
|
+
status: import_zod5.default.string().describe("Current status of the task: pending, in_progress, completed, cancelled"),
|
|
9270
|
+
priority: import_zod5.default.string().describe("Priority level of the task: high, medium, low"),
|
|
9271
|
+
id: import_zod5.default.string().describe("Unique identifier for the todo item")
|
|
9272
|
+
});
|
|
9273
|
+
var TodoWriteTool = new ExuluTool2({
|
|
9274
|
+
id: "todo_write",
|
|
9275
|
+
name: "Todo Write",
|
|
9276
|
+
description: "Use this tool to write your todo list",
|
|
9277
|
+
type: "function",
|
|
9278
|
+
category: "todo",
|
|
9279
|
+
config: [{
|
|
9280
|
+
name: "description",
|
|
9281
|
+
description: "The description of the todo list, if set overwrites the default description.",
|
|
9282
|
+
default: todowrite_default
|
|
9283
|
+
}],
|
|
9284
|
+
inputSchema: import_zod5.default.object({
|
|
9285
|
+
todos: import_zod5.default.array(TodoSchema).describe("The updated todo list")
|
|
9286
|
+
}),
|
|
9287
|
+
execute: async (inputs) => {
|
|
9288
|
+
const { sessionID, todos, user } = inputs;
|
|
9289
|
+
if (!user) {
|
|
9290
|
+
throw new Error("No authenticated user available, a user is required for the todo write tool, this likely means the tool was called outside a session like in an MCP or API call instead of as part of an authenticated session.");
|
|
9291
|
+
}
|
|
9292
|
+
if (!sessionID) {
|
|
9293
|
+
throw new Error("Session ID is required for the todo write tool, this likely means the tool was called outside a session like in an MCP or API call instead of as part of a conversation.");
|
|
9294
|
+
}
|
|
9295
|
+
const session = await getSession({ sessionID });
|
|
9296
|
+
if (!session?.id) {
|
|
9297
|
+
throw new Error("Session with ID " + sessionID + " not found in the todo write tool.");
|
|
9298
|
+
}
|
|
9299
|
+
const hasAccessToSession = await checkRecordAccess(session, "read", user);
|
|
9300
|
+
if (!hasAccessToSession) {
|
|
9301
|
+
throw new Error("You don't have access to this session " + session.id + ".");
|
|
9302
|
+
}
|
|
9303
|
+
await updateTodos({
|
|
9304
|
+
session,
|
|
9305
|
+
todos
|
|
9306
|
+
});
|
|
9307
|
+
return {
|
|
9308
|
+
result: JSON.stringify(todos, null, 2)
|
|
9309
|
+
};
|
|
9310
|
+
}
|
|
9311
|
+
});
|
|
9312
|
+
var TodoReadTool = new ExuluTool2({
|
|
9313
|
+
id: "todo_read",
|
|
9314
|
+
name: "Todo Read",
|
|
9315
|
+
description: "Use this tool to read your todo list",
|
|
9316
|
+
inputSchema: import_zod5.default.object({}),
|
|
9317
|
+
type: "function",
|
|
9318
|
+
category: "todo",
|
|
9319
|
+
config: [{
|
|
9320
|
+
name: "description",
|
|
9321
|
+
description: "The description of the todo list, if set overwrites the default description.",
|
|
9322
|
+
default: todoread_default
|
|
9323
|
+
}],
|
|
9324
|
+
execute: async (inputs) => {
|
|
9325
|
+
const { sessionID } = inputs;
|
|
9326
|
+
let todos = await getTodos(sessionID);
|
|
9327
|
+
return {
|
|
9328
|
+
result: JSON.stringify(todos, null, 2)
|
|
9329
|
+
};
|
|
9330
|
+
}
|
|
9331
|
+
});
|
|
9332
|
+
async function updateTodos(input) {
|
|
9333
|
+
const metadata = input.session.metadata || {};
|
|
9334
|
+
metadata["todos"] = input.todos;
|
|
9335
|
+
const { db: db3 } = await postgresClient();
|
|
9336
|
+
await db3.from("agent_sessions").where({ id: input.session.id }).update({
|
|
9337
|
+
metadata
|
|
9338
|
+
});
|
|
9339
|
+
return input.session;
|
|
9340
|
+
}
|
|
9341
|
+
async function getTodos(sessionID) {
|
|
9342
|
+
const { db: db3 } = await postgresClient();
|
|
9343
|
+
const session = await db3.from("agent_sessions").where({ id: sessionID }).first();
|
|
9344
|
+
if (!session) {
|
|
9345
|
+
throw new Error("Session not found for session ID: " + sessionID);
|
|
9346
|
+
}
|
|
9347
|
+
return session.metadata?.todos || [];
|
|
9348
|
+
}
|
|
9349
|
+
var todoTools = [
|
|
9350
|
+
TodoWriteTool,
|
|
9351
|
+
TodoReadTool
|
|
9352
|
+
];
|
|
9353
|
+
|
|
8725
9354
|
// src/registry/index.ts
|
|
8726
9355
|
var isDev = process.env.NODE_ENV !== "production";
|
|
8727
9356
|
var consoleTransport = new import_winston2.default.transports.Console({
|
|
@@ -8794,6 +9423,7 @@ var ExuluApp = class {
|
|
|
8794
9423
|
this._tools = [
|
|
8795
9424
|
...tools ?? [],
|
|
8796
9425
|
...mathTools,
|
|
9426
|
+
...todoTools,
|
|
8797
9427
|
// Add contexts as tools
|
|
8798
9428
|
...Object.values(contexts || {}).map((context) => context.tool())
|
|
8799
9429
|
// Because agents are stored in the database, we add those as tools
|
|
@@ -8905,6 +9535,16 @@ var ExuluApp = class {
|
|
|
8905
9535
|
bullmq = {
|
|
8906
9536
|
workers: {
|
|
8907
9537
|
create: async (queues2) => {
|
|
9538
|
+
console.log(`
|
|
9539
|
+
\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
|
|
9540
|
+
\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
|
|
9541
|
+
\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
|
|
9542
|
+
\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
|
|
9543
|
+
\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
|
|
9544
|
+
\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
|
|
9545
|
+
Intelligence Management Platform - Workers
|
|
9546
|
+
|
|
9547
|
+
`);
|
|
8908
9548
|
if (!this._config) {
|
|
8909
9549
|
throw new Error("Config not initialized, make sure to call await ExuluApp.create() first when starting your server.");
|
|
8910
9550
|
}
|
|
@@ -8926,16 +9566,26 @@ var ExuluApp = class {
|
|
|
8926
9566
|
if (queues2) {
|
|
8927
9567
|
filteredQueues = filteredQueues.filter((q) => queues2.includes(q.queue.name));
|
|
8928
9568
|
}
|
|
8929
|
-
const
|
|
8930
|
-
|
|
8931
|
-
|
|
8932
|
-
|
|
9569
|
+
const contexts = Object.values(this._contexts ?? {});
|
|
9570
|
+
let sources = [];
|
|
9571
|
+
for (const context of contexts) {
|
|
9572
|
+
for (const source of context.sources) {
|
|
9573
|
+
sources.push({
|
|
9574
|
+
...source,
|
|
9575
|
+
context: context.id
|
|
9576
|
+
});
|
|
9577
|
+
}
|
|
9578
|
+
}
|
|
8933
9579
|
if (sources.length > 0) {
|
|
8934
9580
|
console.log("[EXULU] Creating ContextSource schedulers for", sources.length, "sources.");
|
|
8935
9581
|
for (const source of sources) {
|
|
8936
9582
|
const queue = await source.config?.queue;
|
|
9583
|
+
if (!queue) {
|
|
9584
|
+
console.warn("[EXULU] No queue configured for source", source.name);
|
|
9585
|
+
continue;
|
|
9586
|
+
}
|
|
8937
9587
|
if (queue) {
|
|
8938
|
-
if (!source.config
|
|
9588
|
+
if (!source.config?.schedule) {
|
|
8939
9589
|
throw new Error("Schedule is required for source when configuring a queue: " + source.name);
|
|
8940
9590
|
}
|
|
8941
9591
|
console.log("[EXULU] Creating ContextSource scheduler for", source.name, "in queue", queue.queue?.name);
|
|
@@ -8947,7 +9597,8 @@ var ExuluApp = class {
|
|
|
8947
9597
|
data: {
|
|
8948
9598
|
source: source.id,
|
|
8949
9599
|
context: source.context,
|
|
8950
|
-
type: "source"
|
|
9600
|
+
type: "source",
|
|
9601
|
+
inputs: {}
|
|
8951
9602
|
},
|
|
8952
9603
|
opts: {
|
|
8953
9604
|
backoff: {
|
|
@@ -10233,7 +10884,9 @@ var {
|
|
|
10233
10884
|
workflowTemplatesSchema: workflowTemplatesSchema3,
|
|
10234
10885
|
rbacSchema: rbacSchema3,
|
|
10235
10886
|
projectsSchema: projectsSchema3,
|
|
10236
|
-
jobResultsSchema: jobResultsSchema3
|
|
10887
|
+
jobResultsSchema: jobResultsSchema3,
|
|
10888
|
+
promptLibrarySchema: promptLibrarySchema3,
|
|
10889
|
+
promptFavoritesSchema: promptFavoritesSchema3
|
|
10237
10890
|
} = coreSchemas.get();
|
|
10238
10891
|
var addMissingFields = async (knex, tableName, fields, skipFields = []) => {
|
|
10239
10892
|
for (const field of fields) {
|
|
@@ -10268,6 +10921,8 @@ var up = async function(knex) {
|
|
|
10268
10921
|
statisticsSchema3(),
|
|
10269
10922
|
projectsSchema3(),
|
|
10270
10923
|
jobResultsSchema3(),
|
|
10924
|
+
promptLibrarySchema3(),
|
|
10925
|
+
promptFavoritesSchema3(),
|
|
10271
10926
|
rbacSchema3(),
|
|
10272
10927
|
agentsSchema3(),
|
|
10273
10928
|
variablesSchema3(),
|
|
@@ -10370,20 +11025,39 @@ var execute = async ({ contexts }) => {
|
|
|
10370
11025
|
await up(db3);
|
|
10371
11026
|
await contextDatabases(contexts);
|
|
10372
11027
|
console.log("[EXULU] Inserting default user and admin role.");
|
|
10373
|
-
const
|
|
10374
|
-
|
|
10375
|
-
|
|
10376
|
-
|
|
11028
|
+
const existingAdminRole = await db3.from("roles").where({ name: "admin" }).first();
|
|
11029
|
+
const existingDefaultRole = await db3.from("roles").where({ name: "default" }).first();
|
|
11030
|
+
let adminRoleId;
|
|
11031
|
+
let defaultRoleId;
|
|
11032
|
+
if (!existingAdminRole) {
|
|
11033
|
+
console.log("[EXULU] Creating admin role.");
|
|
10377
11034
|
const role = await db3.from("roles").insert({
|
|
10378
11035
|
name: "admin",
|
|
10379
11036
|
agents: "write",
|
|
11037
|
+
api: "write",
|
|
10380
11038
|
workflows: "write",
|
|
10381
11039
|
variables: "write",
|
|
10382
|
-
users: "write"
|
|
11040
|
+
users: "write",
|
|
11041
|
+
evals: "write"
|
|
10383
11042
|
}).returning("id");
|
|
10384
|
-
|
|
11043
|
+
adminRoleId = role[0].id;
|
|
10385
11044
|
} else {
|
|
10386
|
-
|
|
11045
|
+
adminRoleId = existingAdminRole.id;
|
|
11046
|
+
}
|
|
11047
|
+
if (!existingDefaultRole) {
|
|
11048
|
+
console.log("[EXULU] Creating default role.");
|
|
11049
|
+
const role = await db3.from("roles").insert({
|
|
11050
|
+
name: "default",
|
|
11051
|
+
agents: "write",
|
|
11052
|
+
api: "read",
|
|
11053
|
+
workflows: "read",
|
|
11054
|
+
variables: "read",
|
|
11055
|
+
users: "read",
|
|
11056
|
+
evals: "read"
|
|
11057
|
+
}).returning("id");
|
|
11058
|
+
defaultRoleId = role[0].id;
|
|
11059
|
+
} else {
|
|
11060
|
+
defaultRoleId = existingDefaultRole.id;
|
|
10387
11061
|
}
|
|
10388
11062
|
const existingUser = await db3.from("users").where({ email: "admin@exulu.com" }).first();
|
|
10389
11063
|
if (!existingUser) {
|
|
@@ -10398,7 +11072,7 @@ var execute = async ({ contexts }) => {
|
|
|
10398
11072
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
10399
11073
|
password,
|
|
10400
11074
|
type: "user",
|
|
10401
|
-
role:
|
|
11075
|
+
role: adminRoleId
|
|
10402
11076
|
});
|
|
10403
11077
|
}
|
|
10404
11078
|
const { key } = await generateApiKey("exulu", "api@exulu.com");
|