@exulu/backend 1.33.0 → 1.34.1
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 +246 -29
- package/dist/index.js +246 -29
- package/package.json +1 -1
- package/types/models/eval-run.ts +7 -4
package/.mcp.json
ADDED
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
## [1.34.1](https://github.com/Qventu/exulu-backend/compare/v1.34.0...v1.34.1) (2025-11-17)
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
###
|
|
4
|
+
### Bug Fixes
|
|
5
5
|
|
|
6
|
-
*
|
|
6
|
+
* project tracking anthropic passthrough and timeout for worker ([d0c39c8](https://github.com/Qventu/exulu-backend/commit/d0c39c8dec082a098b91958d9b2fa31baa31b59e))
|
package/dist/index.cjs
CHANGED
|
@@ -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.");
|
|
@@ -1379,6 +1379,69 @@ var platformConfigurationsSchema = {
|
|
|
1379
1379
|
}
|
|
1380
1380
|
]
|
|
1381
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
|
+
};
|
|
1382
1445
|
var addCoreFields = (schema) => {
|
|
1383
1446
|
schema.fields.forEach((field) => {
|
|
1384
1447
|
if (field.type === "file") {
|
|
@@ -1422,7 +1485,9 @@ var coreSchemas = {
|
|
|
1422
1485
|
rbacSchema: () => addCoreFields(rbacSchema),
|
|
1423
1486
|
workflowTemplatesSchema: () => addCoreFields(workflowTemplatesSchema),
|
|
1424
1487
|
platformConfigurationsSchema: () => addCoreFields(platformConfigurationsSchema),
|
|
1425
|
-
jobResultsSchema: () => addCoreFields(jobResultsSchema)
|
|
1488
|
+
jobResultsSchema: () => addCoreFields(jobResultsSchema),
|
|
1489
|
+
promptLibrarySchema: () => addCoreFields(promptLibrarySchema),
|
|
1490
|
+
promptFavoritesSchema: () => addCoreFields(promptFavoritesSchema)
|
|
1426
1491
|
};
|
|
1427
1492
|
}
|
|
1428
1493
|
};
|
|
@@ -1882,6 +1947,7 @@ input FilterOperatorJSON {
|
|
|
1882
1947
|
eq: JSON
|
|
1883
1948
|
ne: JSON
|
|
1884
1949
|
in: [JSON]
|
|
1950
|
+
contains: JSON
|
|
1885
1951
|
}
|
|
1886
1952
|
|
|
1887
1953
|
input SortBy {
|
|
@@ -2383,7 +2449,9 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2383
2449
|
source: source.id,
|
|
2384
2450
|
context: exists.id,
|
|
2385
2451
|
type: "source",
|
|
2386
|
-
inputs: args.inputs
|
|
2452
|
+
inputs: args.inputs,
|
|
2453
|
+
user: context.user.id,
|
|
2454
|
+
role: context.user.role?.id
|
|
2387
2455
|
});
|
|
2388
2456
|
console.log("[EXULU] Source function job scheduled", job.id);
|
|
2389
2457
|
return {
|
|
@@ -2412,6 +2480,15 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2412
2480
|
console.log(`[EXULU] created item through source update job ${createdItem.id}`);
|
|
2413
2481
|
}
|
|
2414
2482
|
}
|
|
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
|
+
});
|
|
2415
2492
|
return {
|
|
2416
2493
|
message: "Items created successfully.",
|
|
2417
2494
|
jobs,
|
|
@@ -2446,7 +2523,7 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2446
2523
|
jobs: jobs2.slice(0, 100)
|
|
2447
2524
|
};
|
|
2448
2525
|
}
|
|
2449
|
-
query = applyFilters(query, args.where);
|
|
2526
|
+
query = applyFilters(query, args.where, table);
|
|
2450
2527
|
const items = await query;
|
|
2451
2528
|
if (items.length === 0) {
|
|
2452
2529
|
throw new Error("No items found to generate chunks for.");
|
|
@@ -2481,7 +2558,7 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2481
2558
|
}
|
|
2482
2559
|
let query = db3.from(getTableName(id)).select("id");
|
|
2483
2560
|
if (args.where) {
|
|
2484
|
-
query = applyFilters(query, args.where);
|
|
2561
|
+
query = applyFilters(query, args.where, table);
|
|
2485
2562
|
}
|
|
2486
2563
|
const items = await query;
|
|
2487
2564
|
if (items.length === 0) {
|
|
@@ -2538,18 +2615,38 @@ var applyAccessControl = (table, user, query) => {
|
|
|
2538
2615
|
}
|
|
2539
2616
|
return query;
|
|
2540
2617
|
};
|
|
2541
|
-
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";
|
|
2542
2621
|
if (operators.eq !== void 0) {
|
|
2543
|
-
|
|
2622
|
+
if (isJsonField) {
|
|
2623
|
+
query = query.whereRaw(`?? = ?::jsonb`, [fieldName, JSON.stringify(operators.eq)]);
|
|
2624
|
+
} else {
|
|
2625
|
+
query = query.where(fieldName, operators.eq);
|
|
2626
|
+
}
|
|
2544
2627
|
}
|
|
2545
2628
|
if (operators.ne !== void 0) {
|
|
2546
|
-
|
|
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
|
+
}
|
|
2547
2634
|
}
|
|
2548
2635
|
if (operators.in !== void 0) {
|
|
2549
|
-
|
|
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
|
+
}
|
|
2550
2643
|
}
|
|
2551
2644
|
if (operators.contains !== void 0) {
|
|
2552
|
-
|
|
2645
|
+
if (isJsonField) {
|
|
2646
|
+
query = query.whereRaw(`?? @> ?::jsonb`, [fieldName, JSON.stringify(operators.contains)]);
|
|
2647
|
+
} else {
|
|
2648
|
+
query = query.where(fieldName, "like", `%${operators.contains}%`);
|
|
2649
|
+
}
|
|
2553
2650
|
}
|
|
2554
2651
|
if (operators.lte !== void 0) {
|
|
2555
2652
|
query = query.where(fieldName, "<=", operators.lte);
|
|
@@ -2811,21 +2908,21 @@ var finalizeRequestedFields = async ({
|
|
|
2811
2908
|
}
|
|
2812
2909
|
return result;
|
|
2813
2910
|
};
|
|
2814
|
-
var applyFilters = (query, filters) => {
|
|
2911
|
+
var applyFilters = (query, filters, table) => {
|
|
2815
2912
|
filters.forEach((filter) => {
|
|
2816
2913
|
Object.entries(filter).forEach(([fieldName, operators]) => {
|
|
2817
2914
|
if (operators) {
|
|
2818
2915
|
if (operators.and !== void 0) {
|
|
2819
2916
|
operators.and.forEach((operator) => {
|
|
2820
|
-
query = converOperatorToQuery(query, fieldName, operator);
|
|
2917
|
+
query = converOperatorToQuery(query, fieldName, operator, table);
|
|
2821
2918
|
});
|
|
2822
2919
|
}
|
|
2823
2920
|
if (operators.or !== void 0) {
|
|
2824
2921
|
operators.or.forEach((operator) => {
|
|
2825
|
-
query = converOperatorToQuery(query, fieldName, operator);
|
|
2922
|
+
query = converOperatorToQuery(query, fieldName, operator, table);
|
|
2826
2923
|
});
|
|
2827
2924
|
}
|
|
2828
|
-
query = converOperatorToQuery(query, fieldName, operators);
|
|
2925
|
+
query = converOperatorToQuery(query, fieldName, operators, table);
|
|
2829
2926
|
}
|
|
2830
2927
|
});
|
|
2831
2928
|
});
|
|
@@ -2865,7 +2962,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2865
2962
|
const requestedFields = getRequestedFields(info);
|
|
2866
2963
|
const sanitizedFields = sanitizeRequestedFields(table, requestedFields);
|
|
2867
2964
|
let query = db3.from(tableNamePlural).select(sanitizedFields);
|
|
2868
|
-
query = applyFilters(query, filters);
|
|
2965
|
+
query = applyFilters(query, filters, table);
|
|
2869
2966
|
query = applyAccessControl(table, context.user, query);
|
|
2870
2967
|
query = applySorting(query, sort);
|
|
2871
2968
|
let result = await query.first();
|
|
@@ -2878,7 +2975,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2878
2975
|
throw new Error("Limit cannot be greater than 500.");
|
|
2879
2976
|
}
|
|
2880
2977
|
let countQuery = db3(tableNamePlural);
|
|
2881
|
-
countQuery = applyFilters(countQuery, filters);
|
|
2978
|
+
countQuery = applyFilters(countQuery, filters, table);
|
|
2882
2979
|
countQuery = applyAccessControl(table, context.user, countQuery);
|
|
2883
2980
|
const countResult = await countQuery.count("* as count");
|
|
2884
2981
|
const itemCount = Number(countResult[0]?.count || 0);
|
|
@@ -2887,7 +2984,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2887
2984
|
const hasPreviousPage = currentPage > 1;
|
|
2888
2985
|
const hasNextPage = currentPage < pageCount - 1;
|
|
2889
2986
|
let dataQuery = db3(tableNamePlural);
|
|
2890
|
-
dataQuery = applyFilters(dataQuery, filters);
|
|
2987
|
+
dataQuery = applyFilters(dataQuery, filters, table);
|
|
2891
2988
|
dataQuery = applyAccessControl(table, context.user, dataQuery);
|
|
2892
2989
|
const requestedFields = getRequestedFields(info);
|
|
2893
2990
|
dataQuery = applySorting(dataQuery, sort);
|
|
@@ -2912,7 +3009,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2912
3009
|
const { filters = [], groupBy } = args;
|
|
2913
3010
|
const { db: db3 } = context;
|
|
2914
3011
|
let query = db3(tableNamePlural);
|
|
2915
|
-
query = applyFilters(query, filters);
|
|
3012
|
+
query = applyFilters(query, filters, table);
|
|
2916
3013
|
query = applyAccessControl(table, context.user, query);
|
|
2917
3014
|
if (groupBy) {
|
|
2918
3015
|
query = query.select(groupBy).groupBy(groupBy);
|
|
@@ -3012,11 +3109,11 @@ var vectorSearch = async ({
|
|
|
3012
3109
|
const mainTable = getTableName(id);
|
|
3013
3110
|
const chunksTable = getChunksTableName(id);
|
|
3014
3111
|
let countQuery = db3(mainTable);
|
|
3015
|
-
countQuery = applyFilters(countQuery, filters);
|
|
3112
|
+
countQuery = applyFilters(countQuery, filters, table);
|
|
3016
3113
|
countQuery = applyAccessControl(table, user, countQuery);
|
|
3017
3114
|
const columns = await db3(mainTable).columnInfo();
|
|
3018
3115
|
let itemsQuery = db3(mainTable).select(Object.keys(columns).map((column) => mainTable + "." + column));
|
|
3019
|
-
itemsQuery = applyFilters(itemsQuery, filters);
|
|
3116
|
+
itemsQuery = applyFilters(itemsQuery, filters, table);
|
|
3020
3117
|
itemsQuery = applyAccessControl(table, user, itemsQuery);
|
|
3021
3118
|
itemsQuery = applySorting(itemsQuery, sort);
|
|
3022
3119
|
if (queryRewriter) {
|
|
@@ -3777,7 +3874,7 @@ type PageInfo {
|
|
|
3777
3874
|
const {
|
|
3778
3875
|
jobs,
|
|
3779
3876
|
count
|
|
3780
|
-
} = await
|
|
3877
|
+
} = await getJobsByQueueName(
|
|
3781
3878
|
args.queue,
|
|
3782
3879
|
args.statusses,
|
|
3783
3880
|
args.page || 1,
|
|
@@ -4210,7 +4307,7 @@ var validateCreateOrRemoveSuperAdminPermission = async (tableNamePlural, input,
|
|
|
4210
4307
|
}
|
|
4211
4308
|
}
|
|
4212
4309
|
};
|
|
4213
|
-
async function
|
|
4310
|
+
async function getJobsByQueueName(queueName, statusses, page, limit) {
|
|
4214
4311
|
const queue = queues.list.get(queueName);
|
|
4215
4312
|
if (!queue) {
|
|
4216
4313
|
throw new Error(`Queue ${queueName} not found`);
|
|
@@ -5681,6 +5778,9 @@ var ExuluContext = class {
|
|
|
5681
5778
|
};
|
|
5682
5779
|
};
|
|
5683
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
|
+
}
|
|
5684
5784
|
const { db: db3 } = await postgresClient();
|
|
5685
5785
|
const mutation = db3.from(getTableName(
|
|
5686
5786
|
this.id
|
|
@@ -5965,6 +6065,7 @@ var ExuluContext = class {
|
|
|
5965
6065
|
};
|
|
5966
6066
|
};
|
|
5967
6067
|
var updateStatistic = async (statistic) => {
|
|
6068
|
+
console.log("[EXULU] updating statistic", statistic);
|
|
5968
6069
|
const currentDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
5969
6070
|
const { db: db3 } = await postgresClient();
|
|
5970
6071
|
const existing = await db3.from("tracking").where({
|
|
@@ -6108,6 +6209,8 @@ var {
|
|
|
6108
6209
|
variablesSchema: variablesSchema2,
|
|
6109
6210
|
workflowTemplatesSchema: workflowTemplatesSchema2,
|
|
6110
6211
|
rbacSchema: rbacSchema2,
|
|
6212
|
+
promptLibrarySchema: promptLibrarySchema2,
|
|
6213
|
+
promptFavoritesSchema: promptFavoritesSchema2,
|
|
6111
6214
|
statisticsSchema: statisticsSchema2
|
|
6112
6215
|
} = coreSchemas.get();
|
|
6113
6216
|
var createExpressRoutes = async (app, agents, tools, contexts, config, evals, tracer, queues2) => {
|
|
@@ -6138,6 +6241,8 @@ var createExpressRoutes = async (app, agents, tools, contexts, config, evals, tr
|
|
|
6138
6241
|
agentsSchema2(),
|
|
6139
6242
|
projectsSchema2(),
|
|
6140
6243
|
jobResultsSchema2(),
|
|
6244
|
+
promptLibrarySchema2(),
|
|
6245
|
+
promptFavoritesSchema2(),
|
|
6141
6246
|
evalRunsSchema2(),
|
|
6142
6247
|
platformConfigurationsSchema2(),
|
|
6143
6248
|
evalSetsSchema2(),
|
|
@@ -6548,7 +6653,7 @@ Mood: friendly and intelligent.
|
|
|
6548
6653
|
return;
|
|
6549
6654
|
}
|
|
6550
6655
|
let project = null;
|
|
6551
|
-
if (!req.
|
|
6656
|
+
if (!req.params.project || req.params.project === "DEFAULT") {
|
|
6552
6657
|
project = null;
|
|
6553
6658
|
} else {
|
|
6554
6659
|
let projectQuery = db3("projects");
|
|
@@ -6825,7 +6930,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6825
6930
|
}));
|
|
6826
6931
|
const { db: db3 } = await postgresClient();
|
|
6827
6932
|
const data = bullmqJob.data;
|
|
6828
|
-
const timeoutMs = data.timeoutInSeconds * 1e3;
|
|
6933
|
+
const timeoutMs = (data.timeoutInSeconds || 300) * 1e3;
|
|
6829
6934
|
const timeoutPromise = new Promise((_, reject) => {
|
|
6830
6935
|
setTimeout(() => {
|
|
6831
6936
|
reject(new Error(`Timeout for job ${bullmqJob.id} reached after ${data.timeoutInSeconds}s`));
|
|
@@ -6916,6 +7021,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6916
7021
|
const label = `eval-run-${data.eval_run_id}-${data.test_case_id}`;
|
|
6917
7022
|
const existingResult = await db3.from("job_results").where({ label }).first();
|
|
6918
7023
|
if (existingResult) {
|
|
7024
|
+
console.log("[EXULU] found existing job result, so ");
|
|
6919
7025
|
await db3.from("job_results").where({ label }).update({
|
|
6920
7026
|
job_id: bullmqJob.id,
|
|
6921
7027
|
label,
|
|
@@ -7017,6 +7123,8 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7017
7123
|
test_case_id: testCase.id,
|
|
7018
7124
|
eval_run_id: evalRun.id,
|
|
7019
7125
|
eval_function_id: evalFunction.id,
|
|
7126
|
+
eval_function_name: evalFunction.name,
|
|
7127
|
+
eval_function_config: evalFunction.config || {},
|
|
7020
7128
|
result: result2 || 0
|
|
7021
7129
|
};
|
|
7022
7130
|
console.log(`[EXULU] eval function ${evalFunction.id} result: ${result2}`, logMetadata2(bullmqJob.name, {
|
|
@@ -7044,22 +7152,32 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7044
7152
|
}
|
|
7045
7153
|
}
|
|
7046
7154
|
const scores = evalFunctionResults.map((result2) => result2.result);
|
|
7155
|
+
console.log("[EXULU] Exulu eval run scores for test case: " + testCase.id, scores);
|
|
7047
7156
|
let score = 0;
|
|
7048
|
-
switch (data.scoring_method) {
|
|
7157
|
+
switch (data.scoring_method?.toLowerCase()) {
|
|
7049
7158
|
case "median":
|
|
7159
|
+
console.log("[EXULU] Calculating median score");
|
|
7050
7160
|
score = getMedian(scores);
|
|
7051
7161
|
break;
|
|
7052
7162
|
case "average":
|
|
7163
|
+
console.log("[EXULU] Calculating average score");
|
|
7053
7164
|
score = getAverage(scores);
|
|
7054
7165
|
break;
|
|
7055
7166
|
case "sum":
|
|
7167
|
+
console.log("[EXULU] Calculating sum score");
|
|
7056
7168
|
score = getSum(scores);
|
|
7057
7169
|
break;
|
|
7170
|
+
default:
|
|
7171
|
+
console.log("[EXULU] Calculating average score");
|
|
7172
|
+
score = getAverage(scores);
|
|
7058
7173
|
}
|
|
7059
7174
|
return {
|
|
7060
7175
|
result: score,
|
|
7061
7176
|
metadata: {
|
|
7062
|
-
|
|
7177
|
+
messages,
|
|
7178
|
+
function_results: [
|
|
7179
|
+
...evalFunctionResults
|
|
7180
|
+
],
|
|
7063
7181
|
...metadata
|
|
7064
7182
|
}
|
|
7065
7183
|
};
|
|
@@ -7155,6 +7273,15 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7155
7273
|
}));
|
|
7156
7274
|
}
|
|
7157
7275
|
}
|
|
7276
|
+
await updateStatistic({
|
|
7277
|
+
name: "count",
|
|
7278
|
+
label: source.id,
|
|
7279
|
+
type: STATISTICS_TYPE_ENUM.SOURCE_UPDATE,
|
|
7280
|
+
trigger: "api",
|
|
7281
|
+
count: 1,
|
|
7282
|
+
user: data?.user,
|
|
7283
|
+
role: data?.role
|
|
7284
|
+
});
|
|
7158
7285
|
return {
|
|
7159
7286
|
result,
|
|
7160
7287
|
metadata: {
|
|
@@ -7592,6 +7719,92 @@ var ExuluMCP = class {
|
|
|
7592
7719
|
});
|
|
7593
7720
|
server.tools[tool2.id] = tool2.name;
|
|
7594
7721
|
}
|
|
7722
|
+
const getListOfPromptTemplatesName = "getListOfPromptTemplates";
|
|
7723
|
+
if (!server.tools[getListOfPromptTemplatesName]) {
|
|
7724
|
+
server.mcp.registerTool(getListOfPromptTemplatesName, {
|
|
7725
|
+
title: "Get List of Prompt Templates",
|
|
7726
|
+
description: "Retrieves a list of prompt templates available for this agent. Returns the name, description, and ID of each template.",
|
|
7727
|
+
inputSchema: {
|
|
7728
|
+
inputs: import_zod2.z.object({})
|
|
7729
|
+
}
|
|
7730
|
+
}, async ({ inputs }, args) => {
|
|
7731
|
+
console.log("[EXULU] Getting list of prompt templates for agent", agentInstance.id);
|
|
7732
|
+
const { db: db4 } = await postgresClient();
|
|
7733
|
+
const prompts = await db4.from("prompt_library").select("id", "name", "description").whereRaw("assigned_agents @> ?::jsonb", [JSON.stringify(agentInstance.id)]).orderBy("updatedAt", "desc");
|
|
7734
|
+
console.log("[EXULU] Found", prompts.length, "prompt templates");
|
|
7735
|
+
return {
|
|
7736
|
+
content: [{
|
|
7737
|
+
type: "text",
|
|
7738
|
+
text: JSON.stringify({
|
|
7739
|
+
prompts: prompts.map((p) => ({
|
|
7740
|
+
id: p.id,
|
|
7741
|
+
name: p.name,
|
|
7742
|
+
description: p.description || "No description provided"
|
|
7743
|
+
})),
|
|
7744
|
+
count: prompts.length
|
|
7745
|
+
}, null, 2)
|
|
7746
|
+
}],
|
|
7747
|
+
structuredContent: {
|
|
7748
|
+
prompts: prompts.map((p) => ({
|
|
7749
|
+
id: p.id,
|
|
7750
|
+
name: p.name,
|
|
7751
|
+
description: p.description || "No description provided"
|
|
7752
|
+
})),
|
|
7753
|
+
count: prompts.length
|
|
7754
|
+
}
|
|
7755
|
+
};
|
|
7756
|
+
});
|
|
7757
|
+
}
|
|
7758
|
+
const getPromptTemplateDetailsName = "getPromptTemplateDetails";
|
|
7759
|
+
if (!server.tools[getPromptTemplateDetailsName]) {
|
|
7760
|
+
server.mcp.registerTool(getPromptTemplateDetailsName, {
|
|
7761
|
+
title: "Get Prompt Template Details",
|
|
7762
|
+
description: "Retrieves the full details of a specific prompt template by ID, including the actual template content with variables.",
|
|
7763
|
+
inputSchema: {
|
|
7764
|
+
inputs: import_zod2.z.object({
|
|
7765
|
+
id: import_zod2.z.string().describe("The ID of the prompt template to retrieve")
|
|
7766
|
+
})
|
|
7767
|
+
}
|
|
7768
|
+
}, async ({ inputs }, args) => {
|
|
7769
|
+
console.log("[EXULU] Getting prompt template details for ID", inputs.id);
|
|
7770
|
+
const { db: db4 } = await postgresClient();
|
|
7771
|
+
const prompt = await db4.from("prompt_library").select("id", "name", "description", "content", "createdAt", "updatedAt", "usage_count", "favorite_count").where({ id: inputs.id }).first();
|
|
7772
|
+
if (!prompt) {
|
|
7773
|
+
throw new Error(`Prompt template with ID ${inputs.id} not found`);
|
|
7774
|
+
}
|
|
7775
|
+
const isAssignedToAgent = await db4.from("prompt_library").select("id").where({ id: inputs.id }).whereRaw("assigned_agents @> ?::jsonb", [JSON.stringify(agentInstance.id)]).first();
|
|
7776
|
+
console.log("[EXULU] Prompt template found:", prompt.name);
|
|
7777
|
+
return {
|
|
7778
|
+
content: [{
|
|
7779
|
+
type: "text",
|
|
7780
|
+
text: JSON.stringify({
|
|
7781
|
+
id: prompt.id,
|
|
7782
|
+
name: prompt.name,
|
|
7783
|
+
description: prompt.description || "No description provided",
|
|
7784
|
+
content: prompt.content,
|
|
7785
|
+
createdAt: prompt.createdAt,
|
|
7786
|
+
updatedAt: prompt.updatedAt,
|
|
7787
|
+
usageCount: prompt.usage_count || 0,
|
|
7788
|
+
favoriteCount: prompt.favorite_count || 0,
|
|
7789
|
+
isAssignedToThisAgent: !!isAssignedToAgent
|
|
7790
|
+
}, null, 2)
|
|
7791
|
+
}],
|
|
7792
|
+
structuredContent: {
|
|
7793
|
+
id: prompt.id,
|
|
7794
|
+
name: prompt.name,
|
|
7795
|
+
description: prompt.description || "No description provided",
|
|
7796
|
+
content: prompt.content,
|
|
7797
|
+
createdAt: prompt.createdAt,
|
|
7798
|
+
updatedAt: prompt.updatedAt,
|
|
7799
|
+
usageCount: prompt.usage_count || 0,
|
|
7800
|
+
favoriteCount: prompt.favorite_count || 0,
|
|
7801
|
+
isAssignedToThisAgent: !!isAssignedToAgent
|
|
7802
|
+
}
|
|
7803
|
+
};
|
|
7804
|
+
});
|
|
7805
|
+
}
|
|
7806
|
+
server.tools[getListOfPromptTemplatesName] = getListOfPromptTemplatesName;
|
|
7807
|
+
server.tools[getPromptTemplateDetailsName] = getPromptTemplateDetailsName;
|
|
7595
7808
|
return server.mcp;
|
|
7596
7809
|
};
|
|
7597
7810
|
create = async ({ express: express3, allTools, allAgents, allContexts, config }) => {
|
|
@@ -8206,8 +8419,8 @@ var llmAsJudgeEval = () => {
|
|
|
8206
8419
|
console.log("[EXULU] running llm as judge eval", { agent, backend, messages, testCase, config });
|
|
8207
8420
|
let prompt = config?.prompt;
|
|
8208
8421
|
if (!prompt) {
|
|
8209
|
-
console.error("[EXULU] prompt is required.");
|
|
8210
|
-
throw new Error("Prompt is required.");
|
|
8422
|
+
console.error("[EXULU] prompt is required for llm as judge eval but none is provided.");
|
|
8423
|
+
throw new Error("Prompt is required for llm as judge eval but none is provided.");
|
|
8211
8424
|
}
|
|
8212
8425
|
const lastMessage = messages[messages.length - 1]?.parts?.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
8213
8426
|
console.log("[EXULU] last message", lastMessage);
|
|
@@ -10672,7 +10885,9 @@ var {
|
|
|
10672
10885
|
workflowTemplatesSchema: workflowTemplatesSchema3,
|
|
10673
10886
|
rbacSchema: rbacSchema3,
|
|
10674
10887
|
projectsSchema: projectsSchema3,
|
|
10675
|
-
jobResultsSchema: jobResultsSchema3
|
|
10888
|
+
jobResultsSchema: jobResultsSchema3,
|
|
10889
|
+
promptLibrarySchema: promptLibrarySchema3,
|
|
10890
|
+
promptFavoritesSchema: promptFavoritesSchema3
|
|
10676
10891
|
} = coreSchemas.get();
|
|
10677
10892
|
var addMissingFields = async (knex, tableName, fields, skipFields = []) => {
|
|
10678
10893
|
for (const field of fields) {
|
|
@@ -10707,6 +10922,8 @@ var up = async function(knex) {
|
|
|
10707
10922
|
statisticsSchema3(),
|
|
10708
10923
|
projectsSchema3(),
|
|
10709
10924
|
jobResultsSchema3(),
|
|
10925
|
+
promptLibrarySchema3(),
|
|
10926
|
+
promptFavoritesSchema3(),
|
|
10710
10927
|
rbacSchema3(),
|
|
10711
10928
|
agentsSchema3(),
|
|
10712
10929
|
variablesSchema3(),
|
package/dist/index.js
CHANGED
|
@@ -227,7 +227,7 @@ var bullmqDecorator = async ({
|
|
|
227
227
|
embedder,
|
|
228
228
|
workflow,
|
|
229
229
|
processor,
|
|
230
|
-
|
|
230
|
+
evaluation
|
|
231
231
|
];
|
|
232
232
|
if (types.filter((type2) => type2).length > 1) {
|
|
233
233
|
throw new Error("Cannot have multiple types in the same job, must be one of the following: embedder, workflow, processor or eval.");
|
|
@@ -1327,6 +1327,69 @@ var platformConfigurationsSchema = {
|
|
|
1327
1327
|
}
|
|
1328
1328
|
]
|
|
1329
1329
|
};
|
|
1330
|
+
var promptLibrarySchema = {
|
|
1331
|
+
type: "prompt_library",
|
|
1332
|
+
name: {
|
|
1333
|
+
plural: "prompt_library",
|
|
1334
|
+
singular: "prompt_library_item"
|
|
1335
|
+
},
|
|
1336
|
+
RBAC: true,
|
|
1337
|
+
fields: [
|
|
1338
|
+
{
|
|
1339
|
+
name: "name",
|
|
1340
|
+
type: "text",
|
|
1341
|
+
required: true
|
|
1342
|
+
},
|
|
1343
|
+
{
|
|
1344
|
+
name: "description",
|
|
1345
|
+
type: "text"
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
name: "content",
|
|
1349
|
+
type: "longText",
|
|
1350
|
+
required: true
|
|
1351
|
+
},
|
|
1352
|
+
{
|
|
1353
|
+
name: "tags",
|
|
1354
|
+
type: "json"
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
name: "usage_count",
|
|
1358
|
+
type: "number",
|
|
1359
|
+
default: 0
|
|
1360
|
+
},
|
|
1361
|
+
{
|
|
1362
|
+
name: "favorite_count",
|
|
1363
|
+
type: "number",
|
|
1364
|
+
default: 0
|
|
1365
|
+
},
|
|
1366
|
+
{
|
|
1367
|
+
name: "assigned_agents",
|
|
1368
|
+
type: "json"
|
|
1369
|
+
}
|
|
1370
|
+
]
|
|
1371
|
+
};
|
|
1372
|
+
var promptFavoritesSchema = {
|
|
1373
|
+
type: "prompt_favorites",
|
|
1374
|
+
name: {
|
|
1375
|
+
plural: "prompt_favorites",
|
|
1376
|
+
singular: "prompt_favorite"
|
|
1377
|
+
},
|
|
1378
|
+
fields: [
|
|
1379
|
+
{
|
|
1380
|
+
name: "user_id",
|
|
1381
|
+
type: "number",
|
|
1382
|
+
required: true,
|
|
1383
|
+
index: true
|
|
1384
|
+
},
|
|
1385
|
+
{
|
|
1386
|
+
name: "prompt_id",
|
|
1387
|
+
type: "uuid",
|
|
1388
|
+
required: true,
|
|
1389
|
+
index: true
|
|
1390
|
+
}
|
|
1391
|
+
]
|
|
1392
|
+
};
|
|
1330
1393
|
var addCoreFields = (schema) => {
|
|
1331
1394
|
schema.fields.forEach((field) => {
|
|
1332
1395
|
if (field.type === "file") {
|
|
@@ -1370,7 +1433,9 @@ var coreSchemas = {
|
|
|
1370
1433
|
rbacSchema: () => addCoreFields(rbacSchema),
|
|
1371
1434
|
workflowTemplatesSchema: () => addCoreFields(workflowTemplatesSchema),
|
|
1372
1435
|
platformConfigurationsSchema: () => addCoreFields(platformConfigurationsSchema),
|
|
1373
|
-
jobResultsSchema: () => addCoreFields(jobResultsSchema)
|
|
1436
|
+
jobResultsSchema: () => addCoreFields(jobResultsSchema),
|
|
1437
|
+
promptLibrarySchema: () => addCoreFields(promptLibrarySchema),
|
|
1438
|
+
promptFavoritesSchema: () => addCoreFields(promptFavoritesSchema)
|
|
1374
1439
|
};
|
|
1375
1440
|
}
|
|
1376
1441
|
};
|
|
@@ -1830,6 +1895,7 @@ input FilterOperatorJSON {
|
|
|
1830
1895
|
eq: JSON
|
|
1831
1896
|
ne: JSON
|
|
1832
1897
|
in: [JSON]
|
|
1898
|
+
contains: JSON
|
|
1833
1899
|
}
|
|
1834
1900
|
|
|
1835
1901
|
input SortBy {
|
|
@@ -2331,7 +2397,9 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2331
2397
|
source: source.id,
|
|
2332
2398
|
context: exists.id,
|
|
2333
2399
|
type: "source",
|
|
2334
|
-
inputs: args.inputs
|
|
2400
|
+
inputs: args.inputs,
|
|
2401
|
+
user: context.user.id,
|
|
2402
|
+
role: context.user.role?.id
|
|
2335
2403
|
});
|
|
2336
2404
|
console.log("[EXULU] Source function job scheduled", job.id);
|
|
2337
2405
|
return {
|
|
@@ -2360,6 +2428,15 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2360
2428
|
console.log(`[EXULU] created item through source update job ${createdItem.id}`);
|
|
2361
2429
|
}
|
|
2362
2430
|
}
|
|
2431
|
+
await updateStatistic({
|
|
2432
|
+
name: "count",
|
|
2433
|
+
label: source.id,
|
|
2434
|
+
type: STATISTICS_TYPE_ENUM.SOURCE_UPDATE,
|
|
2435
|
+
trigger: "api",
|
|
2436
|
+
count: 1,
|
|
2437
|
+
user: context?.user?.id,
|
|
2438
|
+
role: context?.user?.role?.id
|
|
2439
|
+
});
|
|
2363
2440
|
return {
|
|
2364
2441
|
message: "Items created successfully.",
|
|
2365
2442
|
jobs,
|
|
@@ -2394,7 +2471,7 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2394
2471
|
jobs: jobs2.slice(0, 100)
|
|
2395
2472
|
};
|
|
2396
2473
|
}
|
|
2397
|
-
query = applyFilters(query, args.where);
|
|
2474
|
+
query = applyFilters(query, args.where, table);
|
|
2398
2475
|
const items = await query;
|
|
2399
2476
|
if (items.length === 0) {
|
|
2400
2477
|
throw new Error("No items found to generate chunks for.");
|
|
@@ -2429,7 +2506,7 @@ function createMutations(table, agents, contexts, tools, config) {
|
|
|
2429
2506
|
}
|
|
2430
2507
|
let query = db3.from(getTableName(id)).select("id");
|
|
2431
2508
|
if (args.where) {
|
|
2432
|
-
query = applyFilters(query, args.where);
|
|
2509
|
+
query = applyFilters(query, args.where, table);
|
|
2433
2510
|
}
|
|
2434
2511
|
const items = await query;
|
|
2435
2512
|
if (items.length === 0) {
|
|
@@ -2486,18 +2563,38 @@ var applyAccessControl = (table, user, query) => {
|
|
|
2486
2563
|
}
|
|
2487
2564
|
return query;
|
|
2488
2565
|
};
|
|
2489
|
-
var converOperatorToQuery = (query, fieldName, operators) => {
|
|
2566
|
+
var converOperatorToQuery = (query, fieldName, operators, table) => {
|
|
2567
|
+
const field = table?.fields.find((f) => f.name === fieldName);
|
|
2568
|
+
const isJsonField = field?.type === "json";
|
|
2490
2569
|
if (operators.eq !== void 0) {
|
|
2491
|
-
|
|
2570
|
+
if (isJsonField) {
|
|
2571
|
+
query = query.whereRaw(`?? = ?::jsonb`, [fieldName, JSON.stringify(operators.eq)]);
|
|
2572
|
+
} else {
|
|
2573
|
+
query = query.where(fieldName, operators.eq);
|
|
2574
|
+
}
|
|
2492
2575
|
}
|
|
2493
2576
|
if (operators.ne !== void 0) {
|
|
2494
|
-
|
|
2577
|
+
if (isJsonField) {
|
|
2578
|
+
query = query.whereRaw(`?? IS DISTINCT FROM ?::jsonb`, [fieldName, JSON.stringify(operators.ne)]);
|
|
2579
|
+
} else {
|
|
2580
|
+
query = query.whereRaw(`?? IS DISTINCT FROM ?`, [fieldName, operators.ne]);
|
|
2581
|
+
}
|
|
2495
2582
|
}
|
|
2496
2583
|
if (operators.in !== void 0) {
|
|
2497
|
-
|
|
2584
|
+
if (isJsonField) {
|
|
2585
|
+
const conditions = operators.in.map((val) => `?? = ?::jsonb`).join(" OR ");
|
|
2586
|
+
const bindings = operators.in.flatMap((val) => [fieldName, JSON.stringify(val)]);
|
|
2587
|
+
query = query.whereRaw(`(${conditions})`, bindings);
|
|
2588
|
+
} else {
|
|
2589
|
+
query = query.whereIn(fieldName, operators.in);
|
|
2590
|
+
}
|
|
2498
2591
|
}
|
|
2499
2592
|
if (operators.contains !== void 0) {
|
|
2500
|
-
|
|
2593
|
+
if (isJsonField) {
|
|
2594
|
+
query = query.whereRaw(`?? @> ?::jsonb`, [fieldName, JSON.stringify(operators.contains)]);
|
|
2595
|
+
} else {
|
|
2596
|
+
query = query.where(fieldName, "like", `%${operators.contains}%`);
|
|
2597
|
+
}
|
|
2501
2598
|
}
|
|
2502
2599
|
if (operators.lte !== void 0) {
|
|
2503
2600
|
query = query.where(fieldName, "<=", operators.lte);
|
|
@@ -2759,21 +2856,21 @@ var finalizeRequestedFields = async ({
|
|
|
2759
2856
|
}
|
|
2760
2857
|
return result;
|
|
2761
2858
|
};
|
|
2762
|
-
var applyFilters = (query, filters) => {
|
|
2859
|
+
var applyFilters = (query, filters, table) => {
|
|
2763
2860
|
filters.forEach((filter) => {
|
|
2764
2861
|
Object.entries(filter).forEach(([fieldName, operators]) => {
|
|
2765
2862
|
if (operators) {
|
|
2766
2863
|
if (operators.and !== void 0) {
|
|
2767
2864
|
operators.and.forEach((operator) => {
|
|
2768
|
-
query = converOperatorToQuery(query, fieldName, operator);
|
|
2865
|
+
query = converOperatorToQuery(query, fieldName, operator, table);
|
|
2769
2866
|
});
|
|
2770
2867
|
}
|
|
2771
2868
|
if (operators.or !== void 0) {
|
|
2772
2869
|
operators.or.forEach((operator) => {
|
|
2773
|
-
query = converOperatorToQuery(query, fieldName, operator);
|
|
2870
|
+
query = converOperatorToQuery(query, fieldName, operator, table);
|
|
2774
2871
|
});
|
|
2775
2872
|
}
|
|
2776
|
-
query = converOperatorToQuery(query, fieldName, operators);
|
|
2873
|
+
query = converOperatorToQuery(query, fieldName, operators, table);
|
|
2777
2874
|
}
|
|
2778
2875
|
});
|
|
2779
2876
|
});
|
|
@@ -2813,7 +2910,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2813
2910
|
const requestedFields = getRequestedFields(info);
|
|
2814
2911
|
const sanitizedFields = sanitizeRequestedFields(table, requestedFields);
|
|
2815
2912
|
let query = db3.from(tableNamePlural).select(sanitizedFields);
|
|
2816
|
-
query = applyFilters(query, filters);
|
|
2913
|
+
query = applyFilters(query, filters, table);
|
|
2817
2914
|
query = applyAccessControl(table, context.user, query);
|
|
2818
2915
|
query = applySorting(query, sort);
|
|
2819
2916
|
let result = await query.first();
|
|
@@ -2826,7 +2923,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2826
2923
|
throw new Error("Limit cannot be greater than 500.");
|
|
2827
2924
|
}
|
|
2828
2925
|
let countQuery = db3(tableNamePlural);
|
|
2829
|
-
countQuery = applyFilters(countQuery, filters);
|
|
2926
|
+
countQuery = applyFilters(countQuery, filters, table);
|
|
2830
2927
|
countQuery = applyAccessControl(table, context.user, countQuery);
|
|
2831
2928
|
const countResult = await countQuery.count("* as count");
|
|
2832
2929
|
const itemCount = Number(countResult[0]?.count || 0);
|
|
@@ -2835,7 +2932,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2835
2932
|
const hasPreviousPage = currentPage > 1;
|
|
2836
2933
|
const hasNextPage = currentPage < pageCount - 1;
|
|
2837
2934
|
let dataQuery = db3(tableNamePlural);
|
|
2838
|
-
dataQuery = applyFilters(dataQuery, filters);
|
|
2935
|
+
dataQuery = applyFilters(dataQuery, filters, table);
|
|
2839
2936
|
dataQuery = applyAccessControl(table, context.user, dataQuery);
|
|
2840
2937
|
const requestedFields = getRequestedFields(info);
|
|
2841
2938
|
dataQuery = applySorting(dataQuery, sort);
|
|
@@ -2860,7 +2957,7 @@ function createQueries(table, agents, tools, contexts) {
|
|
|
2860
2957
|
const { filters = [], groupBy } = args;
|
|
2861
2958
|
const { db: db3 } = context;
|
|
2862
2959
|
let query = db3(tableNamePlural);
|
|
2863
|
-
query = applyFilters(query, filters);
|
|
2960
|
+
query = applyFilters(query, filters, table);
|
|
2864
2961
|
query = applyAccessControl(table, context.user, query);
|
|
2865
2962
|
if (groupBy) {
|
|
2866
2963
|
query = query.select(groupBy).groupBy(groupBy);
|
|
@@ -2960,11 +3057,11 @@ var vectorSearch = async ({
|
|
|
2960
3057
|
const mainTable = getTableName(id);
|
|
2961
3058
|
const chunksTable = getChunksTableName(id);
|
|
2962
3059
|
let countQuery = db3(mainTable);
|
|
2963
|
-
countQuery = applyFilters(countQuery, filters);
|
|
3060
|
+
countQuery = applyFilters(countQuery, filters, table);
|
|
2964
3061
|
countQuery = applyAccessControl(table, user, countQuery);
|
|
2965
3062
|
const columns = await db3(mainTable).columnInfo();
|
|
2966
3063
|
let itemsQuery = db3(mainTable).select(Object.keys(columns).map((column) => mainTable + "." + column));
|
|
2967
|
-
itemsQuery = applyFilters(itemsQuery, filters);
|
|
3064
|
+
itemsQuery = applyFilters(itemsQuery, filters, table);
|
|
2968
3065
|
itemsQuery = applyAccessControl(table, user, itemsQuery);
|
|
2969
3066
|
itemsQuery = applySorting(itemsQuery, sort);
|
|
2970
3067
|
if (queryRewriter) {
|
|
@@ -3725,7 +3822,7 @@ type PageInfo {
|
|
|
3725
3822
|
const {
|
|
3726
3823
|
jobs,
|
|
3727
3824
|
count
|
|
3728
|
-
} = await
|
|
3825
|
+
} = await getJobsByQueueName(
|
|
3729
3826
|
args.queue,
|
|
3730
3827
|
args.statusses,
|
|
3731
3828
|
args.page || 1,
|
|
@@ -4158,7 +4255,7 @@ var validateCreateOrRemoveSuperAdminPermission = async (tableNamePlural, input,
|
|
|
4158
4255
|
}
|
|
4159
4256
|
}
|
|
4160
4257
|
};
|
|
4161
|
-
async function
|
|
4258
|
+
async function getJobsByQueueName(queueName, statusses, page, limit) {
|
|
4162
4259
|
const queue = queues.list.get(queueName);
|
|
4163
4260
|
if (!queue) {
|
|
4164
4261
|
throw new Error(`Queue ${queueName} not found`);
|
|
@@ -5648,6 +5745,9 @@ var ExuluContext = class {
|
|
|
5648
5745
|
};
|
|
5649
5746
|
};
|
|
5650
5747
|
createItem = async (item, config, user, role, upsert) => {
|
|
5748
|
+
if (upsert && (!item.id && !item.external_id)) {
|
|
5749
|
+
throw new Error("Item id or external id is required for upsert.");
|
|
5750
|
+
}
|
|
5651
5751
|
const { db: db3 } = await postgresClient();
|
|
5652
5752
|
const mutation = db3.from(getTableName(
|
|
5653
5753
|
this.id
|
|
@@ -5932,6 +6032,7 @@ var ExuluContext = class {
|
|
|
5932
6032
|
};
|
|
5933
6033
|
};
|
|
5934
6034
|
var updateStatistic = async (statistic) => {
|
|
6035
|
+
console.log("[EXULU] updating statistic", statistic);
|
|
5935
6036
|
const currentDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
5936
6037
|
const { db: db3 } = await postgresClient();
|
|
5937
6038
|
const existing = await db3.from("tracking").where({
|
|
@@ -6075,6 +6176,8 @@ var {
|
|
|
6075
6176
|
variablesSchema: variablesSchema2,
|
|
6076
6177
|
workflowTemplatesSchema: workflowTemplatesSchema2,
|
|
6077
6178
|
rbacSchema: rbacSchema2,
|
|
6179
|
+
promptLibrarySchema: promptLibrarySchema2,
|
|
6180
|
+
promptFavoritesSchema: promptFavoritesSchema2,
|
|
6078
6181
|
statisticsSchema: statisticsSchema2
|
|
6079
6182
|
} = coreSchemas.get();
|
|
6080
6183
|
var createExpressRoutes = async (app, agents, tools, contexts, config, evals, tracer, queues2) => {
|
|
@@ -6105,6 +6208,8 @@ var createExpressRoutes = async (app, agents, tools, contexts, config, evals, tr
|
|
|
6105
6208
|
agentsSchema2(),
|
|
6106
6209
|
projectsSchema2(),
|
|
6107
6210
|
jobResultsSchema2(),
|
|
6211
|
+
promptLibrarySchema2(),
|
|
6212
|
+
promptFavoritesSchema2(),
|
|
6108
6213
|
evalRunsSchema2(),
|
|
6109
6214
|
platformConfigurationsSchema2(),
|
|
6110
6215
|
evalSetsSchema2(),
|
|
@@ -6515,7 +6620,7 @@ Mood: friendly and intelligent.
|
|
|
6515
6620
|
return;
|
|
6516
6621
|
}
|
|
6517
6622
|
let project = null;
|
|
6518
|
-
if (!req.
|
|
6623
|
+
if (!req.params.project || req.params.project === "DEFAULT") {
|
|
6519
6624
|
project = null;
|
|
6520
6625
|
} else {
|
|
6521
6626
|
let projectQuery = db3("projects");
|
|
@@ -6792,7 +6897,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6792
6897
|
}));
|
|
6793
6898
|
const { db: db3 } = await postgresClient();
|
|
6794
6899
|
const data = bullmqJob.data;
|
|
6795
|
-
const timeoutMs = data.timeoutInSeconds * 1e3;
|
|
6900
|
+
const timeoutMs = (data.timeoutInSeconds || 300) * 1e3;
|
|
6796
6901
|
const timeoutPromise = new Promise((_, reject) => {
|
|
6797
6902
|
setTimeout(() => {
|
|
6798
6903
|
reject(new Error(`Timeout for job ${bullmqJob.id} reached after ${data.timeoutInSeconds}s`));
|
|
@@ -6883,6 +6988,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6883
6988
|
const label = `eval-run-${data.eval_run_id}-${data.test_case_id}`;
|
|
6884
6989
|
const existingResult = await db3.from("job_results").where({ label }).first();
|
|
6885
6990
|
if (existingResult) {
|
|
6991
|
+
console.log("[EXULU] found existing job result, so ");
|
|
6886
6992
|
await db3.from("job_results").where({ label }).update({
|
|
6887
6993
|
job_id: bullmqJob.id,
|
|
6888
6994
|
label,
|
|
@@ -6984,6 +7090,8 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6984
7090
|
test_case_id: testCase.id,
|
|
6985
7091
|
eval_run_id: evalRun.id,
|
|
6986
7092
|
eval_function_id: evalFunction.id,
|
|
7093
|
+
eval_function_name: evalFunction.name,
|
|
7094
|
+
eval_function_config: evalFunction.config || {},
|
|
6987
7095
|
result: result2 || 0
|
|
6988
7096
|
};
|
|
6989
7097
|
console.log(`[EXULU] eval function ${evalFunction.id} result: ${result2}`, logMetadata2(bullmqJob.name, {
|
|
@@ -7011,22 +7119,32 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7011
7119
|
}
|
|
7012
7120
|
}
|
|
7013
7121
|
const scores = evalFunctionResults.map((result2) => result2.result);
|
|
7122
|
+
console.log("[EXULU] Exulu eval run scores for test case: " + testCase.id, scores);
|
|
7014
7123
|
let score = 0;
|
|
7015
|
-
switch (data.scoring_method) {
|
|
7124
|
+
switch (data.scoring_method?.toLowerCase()) {
|
|
7016
7125
|
case "median":
|
|
7126
|
+
console.log("[EXULU] Calculating median score");
|
|
7017
7127
|
score = getMedian(scores);
|
|
7018
7128
|
break;
|
|
7019
7129
|
case "average":
|
|
7130
|
+
console.log("[EXULU] Calculating average score");
|
|
7020
7131
|
score = getAverage(scores);
|
|
7021
7132
|
break;
|
|
7022
7133
|
case "sum":
|
|
7134
|
+
console.log("[EXULU] Calculating sum score");
|
|
7023
7135
|
score = getSum(scores);
|
|
7024
7136
|
break;
|
|
7137
|
+
default:
|
|
7138
|
+
console.log("[EXULU] Calculating average score");
|
|
7139
|
+
score = getAverage(scores);
|
|
7025
7140
|
}
|
|
7026
7141
|
return {
|
|
7027
7142
|
result: score,
|
|
7028
7143
|
metadata: {
|
|
7029
|
-
|
|
7144
|
+
messages,
|
|
7145
|
+
function_results: [
|
|
7146
|
+
...evalFunctionResults
|
|
7147
|
+
],
|
|
7030
7148
|
...metadata
|
|
7031
7149
|
}
|
|
7032
7150
|
};
|
|
@@ -7122,6 +7240,15 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7122
7240
|
}));
|
|
7123
7241
|
}
|
|
7124
7242
|
}
|
|
7243
|
+
await updateStatistic({
|
|
7244
|
+
name: "count",
|
|
7245
|
+
label: source.id,
|
|
7246
|
+
type: STATISTICS_TYPE_ENUM.SOURCE_UPDATE,
|
|
7247
|
+
trigger: "api",
|
|
7248
|
+
count: 1,
|
|
7249
|
+
user: data?.user,
|
|
7250
|
+
role: data?.role
|
|
7251
|
+
});
|
|
7125
7252
|
return {
|
|
7126
7253
|
result,
|
|
7127
7254
|
metadata: {
|
|
@@ -7559,6 +7686,92 @@ var ExuluMCP = class {
|
|
|
7559
7686
|
});
|
|
7560
7687
|
server.tools[tool2.id] = tool2.name;
|
|
7561
7688
|
}
|
|
7689
|
+
const getListOfPromptTemplatesName = "getListOfPromptTemplates";
|
|
7690
|
+
if (!server.tools[getListOfPromptTemplatesName]) {
|
|
7691
|
+
server.mcp.registerTool(getListOfPromptTemplatesName, {
|
|
7692
|
+
title: "Get List of Prompt Templates",
|
|
7693
|
+
description: "Retrieves a list of prompt templates available for this agent. Returns the name, description, and ID of each template.",
|
|
7694
|
+
inputSchema: {
|
|
7695
|
+
inputs: z2.object({})
|
|
7696
|
+
}
|
|
7697
|
+
}, async ({ inputs }, args) => {
|
|
7698
|
+
console.log("[EXULU] Getting list of prompt templates for agent", agentInstance.id);
|
|
7699
|
+
const { db: db4 } = await postgresClient();
|
|
7700
|
+
const prompts = await db4.from("prompt_library").select("id", "name", "description").whereRaw("assigned_agents @> ?::jsonb", [JSON.stringify(agentInstance.id)]).orderBy("updatedAt", "desc");
|
|
7701
|
+
console.log("[EXULU] Found", prompts.length, "prompt templates");
|
|
7702
|
+
return {
|
|
7703
|
+
content: [{
|
|
7704
|
+
type: "text",
|
|
7705
|
+
text: JSON.stringify({
|
|
7706
|
+
prompts: prompts.map((p) => ({
|
|
7707
|
+
id: p.id,
|
|
7708
|
+
name: p.name,
|
|
7709
|
+
description: p.description || "No description provided"
|
|
7710
|
+
})),
|
|
7711
|
+
count: prompts.length
|
|
7712
|
+
}, null, 2)
|
|
7713
|
+
}],
|
|
7714
|
+
structuredContent: {
|
|
7715
|
+
prompts: prompts.map((p) => ({
|
|
7716
|
+
id: p.id,
|
|
7717
|
+
name: p.name,
|
|
7718
|
+
description: p.description || "No description provided"
|
|
7719
|
+
})),
|
|
7720
|
+
count: prompts.length
|
|
7721
|
+
}
|
|
7722
|
+
};
|
|
7723
|
+
});
|
|
7724
|
+
}
|
|
7725
|
+
const getPromptTemplateDetailsName = "getPromptTemplateDetails";
|
|
7726
|
+
if (!server.tools[getPromptTemplateDetailsName]) {
|
|
7727
|
+
server.mcp.registerTool(getPromptTemplateDetailsName, {
|
|
7728
|
+
title: "Get Prompt Template Details",
|
|
7729
|
+
description: "Retrieves the full details of a specific prompt template by ID, including the actual template content with variables.",
|
|
7730
|
+
inputSchema: {
|
|
7731
|
+
inputs: z2.object({
|
|
7732
|
+
id: z2.string().describe("The ID of the prompt template to retrieve")
|
|
7733
|
+
})
|
|
7734
|
+
}
|
|
7735
|
+
}, async ({ inputs }, args) => {
|
|
7736
|
+
console.log("[EXULU] Getting prompt template details for ID", inputs.id);
|
|
7737
|
+
const { db: db4 } = await postgresClient();
|
|
7738
|
+
const prompt = await db4.from("prompt_library").select("id", "name", "description", "content", "createdAt", "updatedAt", "usage_count", "favorite_count").where({ id: inputs.id }).first();
|
|
7739
|
+
if (!prompt) {
|
|
7740
|
+
throw new Error(`Prompt template with ID ${inputs.id} not found`);
|
|
7741
|
+
}
|
|
7742
|
+
const isAssignedToAgent = await db4.from("prompt_library").select("id").where({ id: inputs.id }).whereRaw("assigned_agents @> ?::jsonb", [JSON.stringify(agentInstance.id)]).first();
|
|
7743
|
+
console.log("[EXULU] Prompt template found:", prompt.name);
|
|
7744
|
+
return {
|
|
7745
|
+
content: [{
|
|
7746
|
+
type: "text",
|
|
7747
|
+
text: JSON.stringify({
|
|
7748
|
+
id: prompt.id,
|
|
7749
|
+
name: prompt.name,
|
|
7750
|
+
description: prompt.description || "No description provided",
|
|
7751
|
+
content: prompt.content,
|
|
7752
|
+
createdAt: prompt.createdAt,
|
|
7753
|
+
updatedAt: prompt.updatedAt,
|
|
7754
|
+
usageCount: prompt.usage_count || 0,
|
|
7755
|
+
favoriteCount: prompt.favorite_count || 0,
|
|
7756
|
+
isAssignedToThisAgent: !!isAssignedToAgent
|
|
7757
|
+
}, null, 2)
|
|
7758
|
+
}],
|
|
7759
|
+
structuredContent: {
|
|
7760
|
+
id: prompt.id,
|
|
7761
|
+
name: prompt.name,
|
|
7762
|
+
description: prompt.description || "No description provided",
|
|
7763
|
+
content: prompt.content,
|
|
7764
|
+
createdAt: prompt.createdAt,
|
|
7765
|
+
updatedAt: prompt.updatedAt,
|
|
7766
|
+
usageCount: prompt.usage_count || 0,
|
|
7767
|
+
favoriteCount: prompt.favorite_count || 0,
|
|
7768
|
+
isAssignedToThisAgent: !!isAssignedToAgent
|
|
7769
|
+
}
|
|
7770
|
+
};
|
|
7771
|
+
});
|
|
7772
|
+
}
|
|
7773
|
+
server.tools[getListOfPromptTemplatesName] = getListOfPromptTemplatesName;
|
|
7774
|
+
server.tools[getPromptTemplateDetailsName] = getPromptTemplateDetailsName;
|
|
7562
7775
|
return server.mcp;
|
|
7563
7776
|
};
|
|
7564
7777
|
create = async ({ express: express3, allTools, allAgents, allContexts, config }) => {
|
|
@@ -8173,8 +8386,8 @@ var llmAsJudgeEval = () => {
|
|
|
8173
8386
|
console.log("[EXULU] running llm as judge eval", { agent, backend, messages, testCase, config });
|
|
8174
8387
|
let prompt = config?.prompt;
|
|
8175
8388
|
if (!prompt) {
|
|
8176
|
-
console.error("[EXULU] prompt is required.");
|
|
8177
|
-
throw new Error("Prompt is required.");
|
|
8389
|
+
console.error("[EXULU] prompt is required for llm as judge eval but none is provided.");
|
|
8390
|
+
throw new Error("Prompt is required for llm as judge eval but none is provided.");
|
|
8178
8391
|
}
|
|
8179
8392
|
const lastMessage = messages[messages.length - 1]?.parts?.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
8180
8393
|
console.log("[EXULU] last message", lastMessage);
|
|
@@ -10639,7 +10852,9 @@ var {
|
|
|
10639
10852
|
workflowTemplatesSchema: workflowTemplatesSchema3,
|
|
10640
10853
|
rbacSchema: rbacSchema3,
|
|
10641
10854
|
projectsSchema: projectsSchema3,
|
|
10642
|
-
jobResultsSchema: jobResultsSchema3
|
|
10855
|
+
jobResultsSchema: jobResultsSchema3,
|
|
10856
|
+
promptLibrarySchema: promptLibrarySchema3,
|
|
10857
|
+
promptFavoritesSchema: promptFavoritesSchema3
|
|
10643
10858
|
} = coreSchemas.get();
|
|
10644
10859
|
var addMissingFields = async (knex, tableName, fields, skipFields = []) => {
|
|
10645
10860
|
for (const field of fields) {
|
|
@@ -10674,6 +10889,8 @@ var up = async function(knex) {
|
|
|
10674
10889
|
statisticsSchema3(),
|
|
10675
10890
|
projectsSchema3(),
|
|
10676
10891
|
jobResultsSchema3(),
|
|
10892
|
+
promptLibrarySchema3(),
|
|
10893
|
+
promptFavoritesSchema3(),
|
|
10677
10894
|
rbacSchema3(),
|
|
10678
10895
|
agentsSchema3(),
|
|
10679
10896
|
variablesSchema3(),
|
package/package.json
CHANGED
package/types/models/eval-run.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
export type ScoringMethod = "median" | "sum" | "average"
|
|
2
2
|
|
|
3
|
+
export interface EvalRunEvalFunction {
|
|
4
|
+
id: string
|
|
5
|
+
name: string,
|
|
6
|
+
config: Record<string, any>
|
|
7
|
+
}
|
|
8
|
+
|
|
3
9
|
export interface EvalRun {
|
|
4
10
|
id: string
|
|
5
11
|
name: string
|
|
6
12
|
eval_set_id: string
|
|
7
13
|
agent_id: string
|
|
8
14
|
timeout_in_seconds: number
|
|
9
|
-
eval_functions:
|
|
10
|
-
id: string
|
|
11
|
-
config: Record<string, any>
|
|
12
|
-
}[]
|
|
15
|
+
eval_functions: EvalRunEvalFunction[]
|
|
13
16
|
config?: Record<string, any> // Optional config for eval functions
|
|
14
17
|
scoring_method: ScoringMethod
|
|
15
18
|
pass_threshold: number // 0-100 percentage
|