@exulu/backend 1.33.0 → 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 +2 -2
- package/dist/index.cjs +243 -27
- package/dist/index.js +243 -27
- 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
|
+
# [1.34.0](https://github.com/Qventu/exulu-backend/compare/v1.33.0...v1.34.0) (2025-11-17)
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Features
|
|
5
5
|
|
|
6
|
-
* add
|
|
6
|
+
* add MCP prompt library integration and JSON filtering enhancements ([bb29681](https://github.com/Qventu/exulu-backend/commit/bb296812f559e197b17fb0255e47dda72c64ed3c))
|
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
|
|
@@ -6108,6 +6208,8 @@ var {
|
|
|
6108
6208
|
variablesSchema: variablesSchema2,
|
|
6109
6209
|
workflowTemplatesSchema: workflowTemplatesSchema2,
|
|
6110
6210
|
rbacSchema: rbacSchema2,
|
|
6211
|
+
promptLibrarySchema: promptLibrarySchema2,
|
|
6212
|
+
promptFavoritesSchema: promptFavoritesSchema2,
|
|
6111
6213
|
statisticsSchema: statisticsSchema2
|
|
6112
6214
|
} = coreSchemas.get();
|
|
6113
6215
|
var createExpressRoutes = async (app, agents, tools, contexts, config, evals, tracer, queues2) => {
|
|
@@ -6138,6 +6240,8 @@ var createExpressRoutes = async (app, agents, tools, contexts, config, evals, tr
|
|
|
6138
6240
|
agentsSchema2(),
|
|
6139
6241
|
projectsSchema2(),
|
|
6140
6242
|
jobResultsSchema2(),
|
|
6243
|
+
promptLibrarySchema2(),
|
|
6244
|
+
promptFavoritesSchema2(),
|
|
6141
6245
|
evalRunsSchema2(),
|
|
6142
6246
|
platformConfigurationsSchema2(),
|
|
6143
6247
|
evalSetsSchema2(),
|
|
@@ -6916,6 +7020,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6916
7020
|
const label = `eval-run-${data.eval_run_id}-${data.test_case_id}`;
|
|
6917
7021
|
const existingResult = await db3.from("job_results").where({ label }).first();
|
|
6918
7022
|
if (existingResult) {
|
|
7023
|
+
console.log("[EXULU] found existing job result, so ");
|
|
6919
7024
|
await db3.from("job_results").where({ label }).update({
|
|
6920
7025
|
job_id: bullmqJob.id,
|
|
6921
7026
|
label,
|
|
@@ -7017,6 +7122,8 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7017
7122
|
test_case_id: testCase.id,
|
|
7018
7123
|
eval_run_id: evalRun.id,
|
|
7019
7124
|
eval_function_id: evalFunction.id,
|
|
7125
|
+
eval_function_name: evalFunction.name,
|
|
7126
|
+
eval_function_config: evalFunction.config || {},
|
|
7020
7127
|
result: result2 || 0
|
|
7021
7128
|
};
|
|
7022
7129
|
console.log(`[EXULU] eval function ${evalFunction.id} result: ${result2}`, logMetadata2(bullmqJob.name, {
|
|
@@ -7044,22 +7151,32 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7044
7151
|
}
|
|
7045
7152
|
}
|
|
7046
7153
|
const scores = evalFunctionResults.map((result2) => result2.result);
|
|
7154
|
+
console.log("[EXULU] Exulu eval run scores for test case: " + testCase.id, scores);
|
|
7047
7155
|
let score = 0;
|
|
7048
|
-
switch (data.scoring_method) {
|
|
7156
|
+
switch (data.scoring_method?.toLowerCase()) {
|
|
7049
7157
|
case "median":
|
|
7158
|
+
console.log("[EXULU] Calculating median score");
|
|
7050
7159
|
score = getMedian(scores);
|
|
7051
7160
|
break;
|
|
7052
7161
|
case "average":
|
|
7162
|
+
console.log("[EXULU] Calculating average score");
|
|
7053
7163
|
score = getAverage(scores);
|
|
7054
7164
|
break;
|
|
7055
7165
|
case "sum":
|
|
7166
|
+
console.log("[EXULU] Calculating sum score");
|
|
7056
7167
|
score = getSum(scores);
|
|
7057
7168
|
break;
|
|
7169
|
+
default:
|
|
7170
|
+
console.log("[EXULU] Calculating average score");
|
|
7171
|
+
score = getAverage(scores);
|
|
7058
7172
|
}
|
|
7059
7173
|
return {
|
|
7060
7174
|
result: score,
|
|
7061
7175
|
metadata: {
|
|
7062
|
-
|
|
7176
|
+
messages,
|
|
7177
|
+
function_results: [
|
|
7178
|
+
...evalFunctionResults
|
|
7179
|
+
],
|
|
7063
7180
|
...metadata
|
|
7064
7181
|
}
|
|
7065
7182
|
};
|
|
@@ -7155,6 +7272,15 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7155
7272
|
}));
|
|
7156
7273
|
}
|
|
7157
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
|
+
});
|
|
7158
7284
|
return {
|
|
7159
7285
|
result,
|
|
7160
7286
|
metadata: {
|
|
@@ -7592,6 +7718,92 @@ var ExuluMCP = class {
|
|
|
7592
7718
|
});
|
|
7593
7719
|
server.tools[tool2.id] = tool2.name;
|
|
7594
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;
|
|
7595
7807
|
return server.mcp;
|
|
7596
7808
|
};
|
|
7597
7809
|
create = async ({ express: express3, allTools, allAgents, allContexts, config }) => {
|
|
@@ -8206,8 +8418,8 @@ var llmAsJudgeEval = () => {
|
|
|
8206
8418
|
console.log("[EXULU] running llm as judge eval", { agent, backend, messages, testCase, config });
|
|
8207
8419
|
let prompt = config?.prompt;
|
|
8208
8420
|
if (!prompt) {
|
|
8209
|
-
console.error("[EXULU] prompt is required.");
|
|
8210
|
-
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.");
|
|
8211
8423
|
}
|
|
8212
8424
|
const lastMessage = messages[messages.length - 1]?.parts?.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
8213
8425
|
console.log("[EXULU] last message", lastMessage);
|
|
@@ -10672,7 +10884,9 @@ var {
|
|
|
10672
10884
|
workflowTemplatesSchema: workflowTemplatesSchema3,
|
|
10673
10885
|
rbacSchema: rbacSchema3,
|
|
10674
10886
|
projectsSchema: projectsSchema3,
|
|
10675
|
-
jobResultsSchema: jobResultsSchema3
|
|
10887
|
+
jobResultsSchema: jobResultsSchema3,
|
|
10888
|
+
promptLibrarySchema: promptLibrarySchema3,
|
|
10889
|
+
promptFavoritesSchema: promptFavoritesSchema3
|
|
10676
10890
|
} = coreSchemas.get();
|
|
10677
10891
|
var addMissingFields = async (knex, tableName, fields, skipFields = []) => {
|
|
10678
10892
|
for (const field of fields) {
|
|
@@ -10707,6 +10921,8 @@ var up = async function(knex) {
|
|
|
10707
10921
|
statisticsSchema3(),
|
|
10708
10922
|
projectsSchema3(),
|
|
10709
10923
|
jobResultsSchema3(),
|
|
10924
|
+
promptLibrarySchema3(),
|
|
10925
|
+
promptFavoritesSchema3(),
|
|
10710
10926
|
rbacSchema3(),
|
|
10711
10927
|
agentsSchema3(),
|
|
10712
10928
|
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
|
|
@@ -6075,6 +6175,8 @@ var {
|
|
|
6075
6175
|
variablesSchema: variablesSchema2,
|
|
6076
6176
|
workflowTemplatesSchema: workflowTemplatesSchema2,
|
|
6077
6177
|
rbacSchema: rbacSchema2,
|
|
6178
|
+
promptLibrarySchema: promptLibrarySchema2,
|
|
6179
|
+
promptFavoritesSchema: promptFavoritesSchema2,
|
|
6078
6180
|
statisticsSchema: statisticsSchema2
|
|
6079
6181
|
} = coreSchemas.get();
|
|
6080
6182
|
var createExpressRoutes = async (app, agents, tools, contexts, config, evals, tracer, queues2) => {
|
|
@@ -6105,6 +6207,8 @@ var createExpressRoutes = async (app, agents, tools, contexts, config, evals, tr
|
|
|
6105
6207
|
agentsSchema2(),
|
|
6106
6208
|
projectsSchema2(),
|
|
6107
6209
|
jobResultsSchema2(),
|
|
6210
|
+
promptLibrarySchema2(),
|
|
6211
|
+
promptFavoritesSchema2(),
|
|
6108
6212
|
evalRunsSchema2(),
|
|
6109
6213
|
platformConfigurationsSchema2(),
|
|
6110
6214
|
evalSetsSchema2(),
|
|
@@ -6883,6 +6987,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6883
6987
|
const label = `eval-run-${data.eval_run_id}-${data.test_case_id}`;
|
|
6884
6988
|
const existingResult = await db3.from("job_results").where({ label }).first();
|
|
6885
6989
|
if (existingResult) {
|
|
6990
|
+
console.log("[EXULU] found existing job result, so ");
|
|
6886
6991
|
await db3.from("job_results").where({ label }).update({
|
|
6887
6992
|
job_id: bullmqJob.id,
|
|
6888
6993
|
label,
|
|
@@ -6984,6 +7089,8 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
6984
7089
|
test_case_id: testCase.id,
|
|
6985
7090
|
eval_run_id: evalRun.id,
|
|
6986
7091
|
eval_function_id: evalFunction.id,
|
|
7092
|
+
eval_function_name: evalFunction.name,
|
|
7093
|
+
eval_function_config: evalFunction.config || {},
|
|
6987
7094
|
result: result2 || 0
|
|
6988
7095
|
};
|
|
6989
7096
|
console.log(`[EXULU] eval function ${evalFunction.id} result: ${result2}`, logMetadata2(bullmqJob.name, {
|
|
@@ -7011,22 +7118,32 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7011
7118
|
}
|
|
7012
7119
|
}
|
|
7013
7120
|
const scores = evalFunctionResults.map((result2) => result2.result);
|
|
7121
|
+
console.log("[EXULU] Exulu eval run scores for test case: " + testCase.id, scores);
|
|
7014
7122
|
let score = 0;
|
|
7015
|
-
switch (data.scoring_method) {
|
|
7123
|
+
switch (data.scoring_method?.toLowerCase()) {
|
|
7016
7124
|
case "median":
|
|
7125
|
+
console.log("[EXULU] Calculating median score");
|
|
7017
7126
|
score = getMedian(scores);
|
|
7018
7127
|
break;
|
|
7019
7128
|
case "average":
|
|
7129
|
+
console.log("[EXULU] Calculating average score");
|
|
7020
7130
|
score = getAverage(scores);
|
|
7021
7131
|
break;
|
|
7022
7132
|
case "sum":
|
|
7133
|
+
console.log("[EXULU] Calculating sum score");
|
|
7023
7134
|
score = getSum(scores);
|
|
7024
7135
|
break;
|
|
7136
|
+
default:
|
|
7137
|
+
console.log("[EXULU] Calculating average score");
|
|
7138
|
+
score = getAverage(scores);
|
|
7025
7139
|
}
|
|
7026
7140
|
return {
|
|
7027
7141
|
result: score,
|
|
7028
7142
|
metadata: {
|
|
7029
|
-
|
|
7143
|
+
messages,
|
|
7144
|
+
function_results: [
|
|
7145
|
+
...evalFunctionResults
|
|
7146
|
+
],
|
|
7030
7147
|
...metadata
|
|
7031
7148
|
}
|
|
7032
7149
|
};
|
|
@@ -7122,6 +7239,15 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
|
|
|
7122
7239
|
}));
|
|
7123
7240
|
}
|
|
7124
7241
|
}
|
|
7242
|
+
await updateStatistic({
|
|
7243
|
+
name: "count",
|
|
7244
|
+
label: source.id,
|
|
7245
|
+
type: STATISTICS_TYPE_ENUM.SOURCE_UPDATE,
|
|
7246
|
+
trigger: "api",
|
|
7247
|
+
count: 1,
|
|
7248
|
+
user: data?.user,
|
|
7249
|
+
role: data?.role
|
|
7250
|
+
});
|
|
7125
7251
|
return {
|
|
7126
7252
|
result,
|
|
7127
7253
|
metadata: {
|
|
@@ -7559,6 +7685,92 @@ var ExuluMCP = class {
|
|
|
7559
7685
|
});
|
|
7560
7686
|
server.tools[tool2.id] = tool2.name;
|
|
7561
7687
|
}
|
|
7688
|
+
const getListOfPromptTemplatesName = "getListOfPromptTemplates";
|
|
7689
|
+
if (!server.tools[getListOfPromptTemplatesName]) {
|
|
7690
|
+
server.mcp.registerTool(getListOfPromptTemplatesName, {
|
|
7691
|
+
title: "Get List of Prompt Templates",
|
|
7692
|
+
description: "Retrieves a list of prompt templates available for this agent. Returns the name, description, and ID of each template.",
|
|
7693
|
+
inputSchema: {
|
|
7694
|
+
inputs: z2.object({})
|
|
7695
|
+
}
|
|
7696
|
+
}, async ({ inputs }, args) => {
|
|
7697
|
+
console.log("[EXULU] Getting list of prompt templates for agent", agentInstance.id);
|
|
7698
|
+
const { db: db4 } = await postgresClient();
|
|
7699
|
+
const prompts = await db4.from("prompt_library").select("id", "name", "description").whereRaw("assigned_agents @> ?::jsonb", [JSON.stringify(agentInstance.id)]).orderBy("updatedAt", "desc");
|
|
7700
|
+
console.log("[EXULU] Found", prompts.length, "prompt templates");
|
|
7701
|
+
return {
|
|
7702
|
+
content: [{
|
|
7703
|
+
type: "text",
|
|
7704
|
+
text: JSON.stringify({
|
|
7705
|
+
prompts: prompts.map((p) => ({
|
|
7706
|
+
id: p.id,
|
|
7707
|
+
name: p.name,
|
|
7708
|
+
description: p.description || "No description provided"
|
|
7709
|
+
})),
|
|
7710
|
+
count: prompts.length
|
|
7711
|
+
}, null, 2)
|
|
7712
|
+
}],
|
|
7713
|
+
structuredContent: {
|
|
7714
|
+
prompts: prompts.map((p) => ({
|
|
7715
|
+
id: p.id,
|
|
7716
|
+
name: p.name,
|
|
7717
|
+
description: p.description || "No description provided"
|
|
7718
|
+
})),
|
|
7719
|
+
count: prompts.length
|
|
7720
|
+
}
|
|
7721
|
+
};
|
|
7722
|
+
});
|
|
7723
|
+
}
|
|
7724
|
+
const getPromptTemplateDetailsName = "getPromptTemplateDetails";
|
|
7725
|
+
if (!server.tools[getPromptTemplateDetailsName]) {
|
|
7726
|
+
server.mcp.registerTool(getPromptTemplateDetailsName, {
|
|
7727
|
+
title: "Get Prompt Template Details",
|
|
7728
|
+
description: "Retrieves the full details of a specific prompt template by ID, including the actual template content with variables.",
|
|
7729
|
+
inputSchema: {
|
|
7730
|
+
inputs: z2.object({
|
|
7731
|
+
id: z2.string().describe("The ID of the prompt template to retrieve")
|
|
7732
|
+
})
|
|
7733
|
+
}
|
|
7734
|
+
}, async ({ inputs }, args) => {
|
|
7735
|
+
console.log("[EXULU] Getting prompt template details for ID", inputs.id);
|
|
7736
|
+
const { db: db4 } = await postgresClient();
|
|
7737
|
+
const prompt = await db4.from("prompt_library").select("id", "name", "description", "content", "createdAt", "updatedAt", "usage_count", "favorite_count").where({ id: inputs.id }).first();
|
|
7738
|
+
if (!prompt) {
|
|
7739
|
+
throw new Error(`Prompt template with ID ${inputs.id} not found`);
|
|
7740
|
+
}
|
|
7741
|
+
const isAssignedToAgent = await db4.from("prompt_library").select("id").where({ id: inputs.id }).whereRaw("assigned_agents @> ?::jsonb", [JSON.stringify(agentInstance.id)]).first();
|
|
7742
|
+
console.log("[EXULU] Prompt template found:", prompt.name);
|
|
7743
|
+
return {
|
|
7744
|
+
content: [{
|
|
7745
|
+
type: "text",
|
|
7746
|
+
text: JSON.stringify({
|
|
7747
|
+
id: prompt.id,
|
|
7748
|
+
name: prompt.name,
|
|
7749
|
+
description: prompt.description || "No description provided",
|
|
7750
|
+
content: prompt.content,
|
|
7751
|
+
createdAt: prompt.createdAt,
|
|
7752
|
+
updatedAt: prompt.updatedAt,
|
|
7753
|
+
usageCount: prompt.usage_count || 0,
|
|
7754
|
+
favoriteCount: prompt.favorite_count || 0,
|
|
7755
|
+
isAssignedToThisAgent: !!isAssignedToAgent
|
|
7756
|
+
}, null, 2)
|
|
7757
|
+
}],
|
|
7758
|
+
structuredContent: {
|
|
7759
|
+
id: prompt.id,
|
|
7760
|
+
name: prompt.name,
|
|
7761
|
+
description: prompt.description || "No description provided",
|
|
7762
|
+
content: prompt.content,
|
|
7763
|
+
createdAt: prompt.createdAt,
|
|
7764
|
+
updatedAt: prompt.updatedAt,
|
|
7765
|
+
usageCount: prompt.usage_count || 0,
|
|
7766
|
+
favoriteCount: prompt.favorite_count || 0,
|
|
7767
|
+
isAssignedToThisAgent: !!isAssignedToAgent
|
|
7768
|
+
}
|
|
7769
|
+
};
|
|
7770
|
+
});
|
|
7771
|
+
}
|
|
7772
|
+
server.tools[getListOfPromptTemplatesName] = getListOfPromptTemplatesName;
|
|
7773
|
+
server.tools[getPromptTemplateDetailsName] = getPromptTemplateDetailsName;
|
|
7562
7774
|
return server.mcp;
|
|
7563
7775
|
};
|
|
7564
7776
|
create = async ({ express: express3, allTools, allAgents, allContexts, config }) => {
|
|
@@ -8173,8 +8385,8 @@ var llmAsJudgeEval = () => {
|
|
|
8173
8385
|
console.log("[EXULU] running llm as judge eval", { agent, backend, messages, testCase, config });
|
|
8174
8386
|
let prompt = config?.prompt;
|
|
8175
8387
|
if (!prompt) {
|
|
8176
|
-
console.error("[EXULU] prompt is required.");
|
|
8177
|
-
throw new Error("Prompt is required.");
|
|
8388
|
+
console.error("[EXULU] prompt is required for llm as judge eval but none is provided.");
|
|
8389
|
+
throw new Error("Prompt is required for llm as judge eval but none is provided.");
|
|
8178
8390
|
}
|
|
8179
8391
|
const lastMessage = messages[messages.length - 1]?.parts?.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
8180
8392
|
console.log("[EXULU] last message", lastMessage);
|
|
@@ -10639,7 +10851,9 @@ var {
|
|
|
10639
10851
|
workflowTemplatesSchema: workflowTemplatesSchema3,
|
|
10640
10852
|
rbacSchema: rbacSchema3,
|
|
10641
10853
|
projectsSchema: projectsSchema3,
|
|
10642
|
-
jobResultsSchema: jobResultsSchema3
|
|
10854
|
+
jobResultsSchema: jobResultsSchema3,
|
|
10855
|
+
promptLibrarySchema: promptLibrarySchema3,
|
|
10856
|
+
promptFavoritesSchema: promptFavoritesSchema3
|
|
10643
10857
|
} = coreSchemas.get();
|
|
10644
10858
|
var addMissingFields = async (knex, tableName, fields, skipFields = []) => {
|
|
10645
10859
|
for (const field of fields) {
|
|
@@ -10674,6 +10888,8 @@ var up = async function(knex) {
|
|
|
10674
10888
|
statisticsSchema3(),
|
|
10675
10889
|
projectsSchema3(),
|
|
10676
10890
|
jobResultsSchema3(),
|
|
10891
|
+
promptLibrarySchema3(),
|
|
10892
|
+
promptFavoritesSchema3(),
|
|
10677
10893
|
rbacSchema3(),
|
|
10678
10894
|
agentsSchema3(),
|
|
10679
10895
|
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
|