@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 ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "exulu-mcp-server-default-coding-agent": {
4
+ "type": "http",
5
+ "url": "https://backend.ai.open.de/mcp/76e6a87c-98be-480b-8081-264eb0bb4ecc",
6
+ "headers": {
7
+ "Authorization": "Bearer ${EXULU_TOKEN}"
8
+ }
9
+ }
10
+ }
11
+ }
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
- # [1.33.0](https://github.com/Qventu/exulu-backend/compare/v1.32.1...v1.33.0) (2025-11-14)
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 todo system, enhanced roles, session metadata, and scheduling support ([06cb449](https://github.com/Qventu/exulu-backend/commit/06cb44999d8f0fcbf60c8f5c50fc3a84db4131d9))
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
- eval
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
- query = query.where(fieldName, operators.eq);
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
- query = query.whereRaw(`?? IS DISTINCT FROM ?`, [fieldName, operators.ne]);
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
- query = query.whereIn(fieldName, operators.in);
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
- query = query.where(fieldName, "like", `%${operators.contains}%`);
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 getJobsByQueueAndName(
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 getJobsByQueueAndName(queueName, statusses, page, limit) {
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
- ...evalFunctionResults,
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
- eval
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
- query = query.where(fieldName, operators.eq);
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
- query = query.whereRaw(`?? IS DISTINCT FROM ?`, [fieldName, operators.ne]);
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
- query = query.whereIn(fieldName, operators.in);
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
- query = query.where(fieldName, "like", `%${operators.contains}%`);
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 getJobsByQueueAndName(
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 getJobsByQueueAndName(queueName, statusses, page, limit) {
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
- ...evalFunctionResults,
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@exulu/backend",
3
3
  "author": "Qventu Bv.",
4
- "version": "1.33.0",
4
+ "version": "1.34.0",
5
5
  "main": "./dist/index.js",
6
6
  "private": false,
7
7
  "publishConfig": {
@@ -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