@exulu/backend 1.38.0 → 1.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -167,11 +167,17 @@ async function postgresClient() {
167
167
  pool: {
168
168
  min: 2,
169
169
  max: 20,
170
+ // Increased from 20 to handle more concurrent operations
170
171
  acquireTimeoutMillis: 3e4,
171
172
  createTimeoutMillis: 3e4,
172
173
  idleTimeoutMillis: 3e4,
173
174
  reapIntervalMillis: 1e3,
174
- createRetryIntervalMillis: 200
175
+ createRetryIntervalMillis: 200,
176
+ // Log pool events to help debug connection issues
177
+ afterCreate: (conn, done) => {
178
+ console.log("[EXULU] New database connection created");
179
+ done(null, conn);
180
+ }
175
181
  }
176
182
  });
177
183
  try {
@@ -452,6 +458,8 @@ var authentication = async ({
452
458
  type: "api",
453
459
  id: 192837465,
454
460
  email: "internal@exulu.com",
461
+ firstname: "API",
462
+ lastname: "User",
455
463
  role: {
456
464
  id: "internal",
457
465
  name: "Internal",
@@ -1285,10 +1293,10 @@ var rbacSchema = {
1285
1293
  name: "user_id",
1286
1294
  type: "number"
1287
1295
  },
1288
- {
1289
- name: "project_id",
1290
- type: "uuid"
1291
- },
1296
+ /* {
1297
+ name: "project_id",
1298
+ type: "uuid"
1299
+ }, */
1292
1300
  {
1293
1301
  name: "rights",
1294
1302
  type: "text",
@@ -2198,7 +2206,7 @@ function createMutations(table, agents, contexts, tools, config) {
2198
2206
  });
2199
2207
  return {
2200
2208
  // Filter result to only include requested fields
2201
- item: finalizeRequestedFields({ table, requestedFields, agents, contexts, tools, result: results[0], user: context.user }),
2209
+ item: finalizeRequestedFields({ args, table, requestedFields, agents, contexts, tools, result: results[0], user: context.user }),
2202
2210
  job
2203
2211
  };
2204
2212
  },
@@ -2246,7 +2254,7 @@ function createMutations(table, agents, contexts, tools, config) {
2246
2254
  }
2247
2255
  const { job } = await postprocessUpdate({ table, requestedFields, agents, contexts, tools, result, user: context.user.id, role: context.user.role?.id, config });
2248
2256
  return {
2249
- item: finalizeRequestedFields({ table, requestedFields, agents, contexts, tools, result, user: context.user.id }),
2257
+ item: finalizeRequestedFields({ args, table, requestedFields, agents, contexts, tools, result, user: context.user.id }),
2250
2258
  job
2251
2259
  };
2252
2260
  },
@@ -2287,7 +2295,7 @@ function createMutations(table, agents, contexts, tools, config) {
2287
2295
  const result = await db3.from(tableNamePlural).select(Object.keys(columns)).where({ id }).first();
2288
2296
  const { job } = await postprocessUpdate({ table, requestedFields, agents, contexts, tools, result, user: context.user.id, role: context.user.role?.id, config });
2289
2297
  return {
2290
- item: finalizeRequestedFields({ table, requestedFields, agents, contexts, tools, result, user: context.user.id }),
2298
+ item: finalizeRequestedFields({ args, table, requestedFields, agents, contexts, tools, result, user: context.user.id }),
2291
2299
  job
2292
2300
  };
2293
2301
  },
@@ -2319,7 +2327,7 @@ function createMutations(table, agents, contexts, tools, config) {
2319
2327
  }).del();
2320
2328
  }
2321
2329
  await postprocessDeletion({ table, requestedFields, agents, contexts, tools, result });
2322
- return finalizeRequestedFields({ table, requestedFields, agents, contexts, tools, result, user: context.user.id });
2330
+ return finalizeRequestedFields({ args, table, requestedFields, agents, contexts, tools, result, user: context.user.id });
2323
2331
  },
2324
2332
  [`${tableNamePlural}RemoveOne`]: async (_, args, context, info) => {
2325
2333
  const { where } = args;
@@ -2343,7 +2351,7 @@ function createMutations(table, agents, contexts, tools, config) {
2343
2351
  }
2344
2352
  await db3(tableNamePlural).where(where).del();
2345
2353
  await postprocessDeletion({ table, requestedFields, agents, contexts, tools, result });
2346
- return finalizeRequestedFields({ table, requestedFields, agents, contexts, tools, result, user: context.user.id });
2354
+ return finalizeRequestedFields({ args, table, requestedFields, agents, contexts, tools, result, user: context.user.id });
2347
2355
  }
2348
2356
  };
2349
2357
  if (table.type === "items") {
@@ -2376,20 +2384,20 @@ function createMutations(table, agents, contexts, tools, config) {
2376
2384
  }
2377
2385
  const { db: db3 } = context;
2378
2386
  let query = db3.from(tableNamePlural).select("*").where({ id: args.item });
2379
- query = applyAccessControl(table, context.user, query);
2387
+ query = applyAccessControl(table, query, context.user);
2380
2388
  const item = await query.first();
2381
2389
  if (!item) {
2382
2390
  throw new Error("Item not found, or your user does not have access to it.");
2383
2391
  }
2384
2392
  const { job, result } = await exists.processField(
2385
2393
  "api",
2386
- context.user.id,
2387
- context.user.role?.id,
2388
2394
  {
2389
2395
  ...item,
2390
2396
  field: args.field
2391
2397
  },
2392
- config
2398
+ config,
2399
+ context.user.id,
2400
+ context.user.role?.id
2393
2401
  );
2394
2402
  return {
2395
2403
  message: job ? "Processing job scheduled." : "Item processed successfully.",
@@ -2436,7 +2444,10 @@ function createMutations(table, agents, contexts, tools, config) {
2436
2444
  };
2437
2445
  }
2438
2446
  console.log("[EXULU] Executing source function directly");
2439
- const result = await source.execute(args.inputs);
2447
+ const result = await source.execute({
2448
+ ...args.inputs,
2449
+ exuluConfig: config
2450
+ });
2440
2451
  let jobs = [];
2441
2452
  let items = [];
2442
2453
  for (const item of result) {
@@ -2560,14 +2571,14 @@ function createMutations(table, agents, contexts, tools, config) {
2560
2571
  }
2561
2572
  return mutations;
2562
2573
  }
2563
- var applyAccessControl = (table, user, query) => {
2574
+ var applyAccessControl = (table, query, user) => {
2564
2575
  const tableNamePlural = table.name.plural.toLowerCase();
2565
- if (table.name.plural !== "agent_sessions" && user.super_admin === true) {
2576
+ if (table.name.plural !== "agent_sessions" && user?.super_admin === true) {
2566
2577
  return query;
2567
2578
  }
2568
- console.log("[EXULU] user.role", user.role);
2579
+ console.log("[EXULU] user.role", user?.role);
2569
2580
  console.log("[EXULU] table.name.plural", table.name.plural);
2570
- if (!user.super_admin && (!user.role || !(table.name.plural === "agents" && (user.role.agents === "read" || user.role.agents === "write")) && !(table.name.plural === "workflow_templates" && (user.role.workflows === "read" || user.role.workflows === "write")) && !(table.name.plural === "variables" && (user.role.variables === "read" || user.role.variables === "write")) && !(table.name.plural === "users" && (user.role.users === "read" || user.role.users === "write")) && !((table.name.plural === "test_cases" || table.name.plural === "eval_sets" || table.name.plural === "eval_runs") && (user.role.evals === "read" || user.role.evals === "write")))) {
2581
+ if (!user?.super_admin && (!user?.role || !(table.name.plural === "agents" && (user.role.agents === "read" || user.role.agents === "write")) && !(table.name.plural === "workflow_templates" && (user.role.workflows === "read" || user.role.workflows === "write")) && !(table.name.plural === "variables" && (user.role.variables === "read" || user.role.variables === "write")) && !(table.name.plural === "users" && (user.role.users === "read" || user.role.users === "write")) && !((table.name.plural === "test_cases" || table.name.plural === "eval_sets" || table.name.plural === "eval_runs") && (user.role.evals === "read" || user.role.evals === "write")))) {
2571
2582
  console.error("==== Access control error: no role found or no access to entity type. ====");
2572
2583
  throw new Error("Access control error: no role found or no access to entity type.");
2573
2584
  }
@@ -2656,7 +2667,7 @@ var removeAgentFields = (requestedFields) => {
2656
2667
  filtered.push("backend");
2657
2668
  return filtered;
2658
2669
  };
2659
- var addAgentFields = async (requestedFields, agents, result, tools, user) => {
2670
+ var addAgentFields = async (args, requestedFields, agents, result, tools, user, contexts) => {
2660
2671
  let backend = agents.find((a) => a.id === result?.backend);
2661
2672
  if (requestedFields.includes("providerName")) {
2662
2673
  result.providerName = backend?.providerName || "";
@@ -2703,6 +2714,17 @@ var addAgentFields = async (requestedFields, agents, result, tools, user) => {
2703
2714
  console.log("[EXULU] hydratedTool", hydratedTool);
2704
2715
  return hydratedTool;
2705
2716
  }));
2717
+ if (args.project) {
2718
+ const projectTool = await createProjectRetrievalTool({
2719
+ projectId: args.project,
2720
+ user,
2721
+ role: user.role?.id,
2722
+ contexts
2723
+ });
2724
+ if (projectTool) {
2725
+ result.tools.unshift(projectTool);
2726
+ }
2727
+ }
2706
2728
  result.tools = result.tools.filter((tool2) => tool2 !== null);
2707
2729
  } else {
2708
2730
  result.tools = [];
@@ -2841,6 +2863,7 @@ var postprocessDeletion = async ({
2841
2863
  return result;
2842
2864
  };
2843
2865
  var finalizeRequestedFields = async ({
2866
+ args,
2844
2867
  table,
2845
2868
  requestedFields,
2846
2869
  agents,
@@ -2857,11 +2880,28 @@ var finalizeRequestedFields = async ({
2857
2880
  }
2858
2881
  if (Array.isArray(result)) {
2859
2882
  result = result.map((item) => {
2860
- return finalizeRequestedFields({ table, requestedFields, agents, contexts, tools, result: item, user });
2883
+ return finalizeRequestedFields({
2884
+ args,
2885
+ table,
2886
+ requestedFields,
2887
+ agents,
2888
+ contexts,
2889
+ tools,
2890
+ result: item,
2891
+ user
2892
+ });
2861
2893
  });
2862
2894
  } else {
2863
2895
  if (table.name.singular === "agent") {
2864
- result = await addAgentFields(requestedFields, agents, result, tools, user);
2896
+ result = await addAgentFields(
2897
+ args,
2898
+ requestedFields,
2899
+ agents,
2900
+ result,
2901
+ tools,
2902
+ user,
2903
+ contexts
2904
+ );
2865
2905
  if (!requestedFields.includes("backend")) {
2866
2906
  delete result.backend;
2867
2907
  }
@@ -2938,18 +2978,18 @@ function createQueries(table, agents, tools, contexts) {
2938
2978
  const requestedFields = getRequestedFields(info);
2939
2979
  const sanitizedFields = sanitizeRequestedFields(table, requestedFields);
2940
2980
  let query = db3.from(tableNamePlural).select(sanitizedFields).where({ id: args.id });
2941
- query = applyAccessControl(table, context.user, query);
2981
+ query = applyAccessControl(table, query, context.user);
2942
2982
  let result = await query.first();
2943
- return finalizeRequestedFields({ table, requestedFields, agents, contexts, tools, result, user: context.user });
2983
+ return finalizeRequestedFields({ args, table, requestedFields, agents, contexts, tools, result, user: context.user });
2944
2984
  },
2945
2985
  [`${tableNameSingular}ByIds`]: async (_, args, context, info) => {
2946
2986
  const { db: db3 } = context;
2947
2987
  const requestedFields = getRequestedFields(info);
2948
2988
  const sanitizedFields = sanitizeRequestedFields(table, requestedFields);
2949
2989
  let query = db3.from(tableNamePlural).select(sanitizedFields).whereIn("id", args.ids);
2950
- query = applyAccessControl(table, context.user, query);
2990
+ query = applyAccessControl(table, query, context.user);
2951
2991
  let result = await query;
2952
- return finalizeRequestedFields({ table, requestedFields, agents, contexts, tools, result, user: context.user });
2992
+ return finalizeRequestedFields({ args, table, requestedFields, agents, contexts, tools, result, user: context.user });
2953
2993
  },
2954
2994
  [`${tableNameSingular}One`]: async (_, args, context, info) => {
2955
2995
  const { filters = [], sort } = args;
@@ -2958,10 +2998,10 @@ function createQueries(table, agents, tools, contexts) {
2958
2998
  const sanitizedFields = sanitizeRequestedFields(table, requestedFields);
2959
2999
  let query = db3.from(tableNamePlural).select(sanitizedFields);
2960
3000
  query = applyFilters(query, filters, table);
2961
- query = applyAccessControl(table, context.user, query);
3001
+ query = applyAccessControl(table, query, context.user);
2962
3002
  query = applySorting(query, sort);
2963
3003
  let result = await query.first();
2964
- return finalizeRequestedFields({ table, requestedFields, agents, contexts, tools, result, user: context.user });
3004
+ return finalizeRequestedFields({ args, table, requestedFields, agents, contexts, tools, result, user: context.user });
2965
3005
  },
2966
3006
  [`${tableNamePlural}Pagination`]: async (_, args, context, info) => {
2967
3007
  const { limit = 10, page = 0, filters = [], sort } = args;
@@ -2971,7 +3011,7 @@ function createQueries(table, agents, tools, contexts) {
2971
3011
  }
2972
3012
  let countQuery = db3(tableNamePlural);
2973
3013
  countQuery = applyFilters(countQuery, filters, table);
2974
- countQuery = applyAccessControl(table, context.user, countQuery);
3014
+ countQuery = applyAccessControl(table, countQuery, context.user);
2975
3015
  const countResult = await countQuery.count("* as count");
2976
3016
  const itemCount = Number(countResult[0]?.count || 0);
2977
3017
  const pageCount = Math.ceil(itemCount / limit);
@@ -2980,7 +3020,7 @@ function createQueries(table, agents, tools, contexts) {
2980
3020
  const hasNextPage = currentPage < pageCount - 1;
2981
3021
  let dataQuery = db3(tableNamePlural);
2982
3022
  dataQuery = applyFilters(dataQuery, filters, table);
2983
- dataQuery = applyAccessControl(table, context.user, dataQuery);
3023
+ dataQuery = applyAccessControl(table, dataQuery, context.user);
2984
3024
  const requestedFields = getRequestedFields(info);
2985
3025
  dataQuery = applySorting(dataQuery, sort);
2986
3026
  if (page > 1) {
@@ -2996,7 +3036,7 @@ function createQueries(table, agents, tools, contexts) {
2996
3036
  hasPreviousPage,
2997
3037
  hasNextPage
2998
3038
  },
2999
- items: finalizeRequestedFields({ table, requestedFields, agents, contexts, tools, result: items, user: context.user })
3039
+ items: finalizeRequestedFields({ args, table, requestedFields, agents, contexts, tools, result: items, user: context.user })
3000
3040
  };
3001
3041
  },
3002
3042
  // Add generic statistics query for all tables
@@ -3005,7 +3045,7 @@ function createQueries(table, agents, tools, contexts) {
3005
3045
  const { db: db3 } = context;
3006
3046
  let query = db3(tableNamePlural);
3007
3047
  query = applyFilters(query, filters, table);
3008
- query = applyAccessControl(table, context.user, query);
3048
+ query = applyAccessControl(table, query, context.user);
3009
3049
  if (groupBy) {
3010
3050
  query = query.select(groupBy).groupBy(groupBy);
3011
3051
  if (tableNamePlural === "tracking") {
@@ -3105,11 +3145,11 @@ var vectorSearch = async ({
3105
3145
  const chunksTable = getChunksTableName(id);
3106
3146
  let countQuery = db3(mainTable);
3107
3147
  countQuery = applyFilters(countQuery, filters, table);
3108
- countQuery = applyAccessControl(table, user, countQuery);
3148
+ countQuery = applyAccessControl(table, countQuery, user);
3109
3149
  const columns = await db3(mainTable).columnInfo();
3110
3150
  let itemsQuery = db3(mainTable).select(Object.keys(columns).map((column) => mainTable + "." + column));
3111
3151
  itemsQuery = applyFilters(itemsQuery, filters, table);
3112
- itemsQuery = applyAccessControl(table, user, itemsQuery);
3152
+ itemsQuery = applyAccessControl(table, itemsQuery, user);
3113
3153
  itemsQuery = applySorting(itemsQuery, sort);
3114
3154
  if (queryRewriter) {
3115
3155
  query = await queryRewriter(query);
@@ -3128,7 +3168,7 @@ var vectorSearch = async ({
3128
3168
  const { chunks } = await embedder.generateFromQuery(context.id, query, {
3129
3169
  label: table.name.singular,
3130
3170
  trigger
3131
- }, user.id, role);
3171
+ }, user?.id, role);
3132
3172
  if (!chunks?.[0]?.vector) {
3133
3173
  throw new Error("No vector generated for query.");
3134
3174
  }
@@ -3518,7 +3558,8 @@ function createSDL(tables, contexts, agents, tools, config, evals, queues2) {
3518
3558
  const tableNameSingularUpperCaseFirst = table.name.singular.charAt(0).toUpperCase() + table.name.singular.slice(1);
3519
3559
  const processorFields = table.fields.filter((field) => field.processor?.execute);
3520
3560
  typeDefs += `
3521
- ${tableNameSingular}ById(id: ID!): ${tableNameSingular}
3561
+ ${tableNameSingular === "agent" ? `${tableNameSingular}ById(id: ID!, project: ID): ${tableNameSingular}` : `${tableNameSingular}ById(id: ID!): ${tableNameSingular}`}
3562
+
3522
3563
  ${tableNameSingular}ByIds(ids: [ID!]!): [${tableNameSingular}]!
3523
3564
  ${tableNamePlural}Pagination(limit: Int, page: Int, filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingularUpperCaseFirst}PaginationResult
3524
3565
  ${tableNameSingular}One(filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingular}
@@ -4450,16 +4491,27 @@ var addPrefixToKey = (keyPath, config) => {
4450
4491
  }
4451
4492
  return `${prefix}/${keyPath}`;
4452
4493
  };
4453
- var uploadFile = async (user, file, key, config, options = {}) => {
4454
- console.log("[EXULU] Uploading file to S3", key);
4494
+ var uploadFile = async (file, key, config, options = {}, user) => {
4455
4495
  if (!config.fileUploads) {
4456
- throw new Error("File uploads are not configured");
4496
+ throw new Error("File uploads are not configured (in the exported uploadFile function)");
4457
4497
  }
4458
4498
  const client2 = getS3Client(config);
4459
- let folder = `${user}/`;
4499
+ let defaultBucket = config.fileUploads.s3Bucket;
4500
+ let customBucket = false;
4501
+ if (key.includes("[bucket:")) {
4502
+ console.log("[EXULU] key includes [bucket:name]", key);
4503
+ customBucket = key.split("[bucket:")[1]?.split("]")[0] || "";
4504
+ if (!customBucket?.length) {
4505
+ throw new Error("Invalid key, does not contain a bucket name like '[bucket:name]'.");
4506
+ }
4507
+ key = key.split("]")[1] || "";
4508
+ console.log("[EXULU] custom bucket", customBucket);
4509
+ }
4510
+ let folder = user ? `${user}/` : "";
4460
4511
  const fullKey = addPrefixToKey(!key.includes(folder) ? folder + key : key, config);
4512
+ console.log("[EXULU] uploading file to s3 into bucket", customBucket || defaultBucket, "with key", fullKey);
4461
4513
  const command = new PutObjectCommand({
4462
- Bucket: config.fileUploads.s3Bucket,
4514
+ Bucket: customBucket || defaultBucket,
4463
4515
  Key: fullKey,
4464
4516
  Body: file,
4465
4517
  ContentType: options.contentType,
@@ -4467,6 +4519,10 @@ var uploadFile = async (user, file, key, config, options = {}) => {
4467
4519
  ContentLength: file.byteLength
4468
4520
  });
4469
4521
  await client2.send(command);
4522
+ console.log("[EXULU] file uploaded to s3 into bucket", customBucket || defaultBucket, "with key", fullKey);
4523
+ if (customBucket) {
4524
+ return "[bucket:" + customBucket + "]" + fullKey;
4525
+ }
4470
4526
  return fullKey;
4471
4527
  };
4472
4528
  var createUppyRoutes = async (app, config) => {
@@ -4625,16 +4681,12 @@ var createUppyRoutes = async (app, config) => {
4625
4681
  key = key.split("]")[1] || "";
4626
4682
  console.log("[EXULU] key", key);
4627
4683
  }
4628
- console.log("[EXULU] Getting object metadata from s3", key);
4629
- console.log("[EXULU] bucket", bucket);
4630
- console.log("[EXULU] key", key);
4631
4684
  const client2 = getS3Client(config);
4632
4685
  const command = new HeadObjectCommand({
4633
4686
  Bucket: bucket,
4634
4687
  Key: key
4635
4688
  });
4636
4689
  const response = await client2.send(command);
4637
- console.log("[EXULU] Object metadata from s3", response);
4638
4690
  res.json(response);
4639
4691
  res.end();
4640
4692
  });
@@ -4949,12 +5001,117 @@ function sanitizeToolName(name) {
4949
5001
  }
4950
5002
  return sanitized;
4951
5003
  }
4952
- var convertToolsArrayToObject = (currentTools, allExuluTools, configs, providerapikey, contexts, user, exuluConfig, sessionID, req) => {
5004
+ var projectsCache = /* @__PURE__ */ new Map();
5005
+ var createProjectRetrievalTool = async ({
5006
+ user,
5007
+ role,
5008
+ contexts,
5009
+ projectId
5010
+ }) => {
5011
+ let project;
5012
+ const cachedProject = projectsCache.get(projectId);
5013
+ const OneMinuteAgo = new Date(Date.now() - 1e3 * 60);
5014
+ if (cachedProject && cachedProject.age > OneMinuteAgo) {
5015
+ project = cachedProject.project;
5016
+ } else {
5017
+ const { db: db3 } = await postgresClient();
5018
+ project = await db3.from("projects").where("id", projectId).first();
5019
+ if (project) {
5020
+ projectsCache.set(projectId, {
5021
+ age: /* @__PURE__ */ new Date(),
5022
+ project
5023
+ });
5024
+ } else {
5025
+ return;
5026
+ }
5027
+ }
5028
+ console.log("[EXULU] Project search tool created for project", project);
5029
+ if (!project.project_items?.length) {
5030
+ return;
5031
+ }
5032
+ const projectRetrievalTool = new ExuluTool2({
5033
+ id: "project_information_retrieval_tool_" + projectId,
5034
+ name: "Project information retrieval tool for project " + project.name,
5035
+ description: "This tool retrieves information about a project from conversations and items that were added to the project " + project.name + ".",
5036
+ inputSchema: z.object({
5037
+ query: z.string().describe("The query to retrieve information about the project " + project.name + "."),
5038
+ keywords: z.array(z.string()).describe("The most relevant keywords in the query, such as names of people, companies, products, etc. in the project " + project.name + ".")
5039
+ }),
5040
+ type: "function",
5041
+ category: "project",
5042
+ config: [],
5043
+ execute: async ({ query, keywords }) => {
5044
+ console.log("[EXULU] Project search tool searching for project", project);
5045
+ const items = project.project_items;
5046
+ const set = {};
5047
+ for (const item of items) {
5048
+ const context = item.split("/")[0];
5049
+ if (!context) {
5050
+ throw new Error("The item added to the project does not have a valid gid with the context id as the prefix before the first slash.");
5051
+ }
5052
+ const id = item.split("/")[1];
5053
+ if (set[context]) {
5054
+ set[context].push(id);
5055
+ } else {
5056
+ set[context] = [id];
5057
+ }
5058
+ }
5059
+ console.log("[EXULU] Project search tool searching through contexts", Object.keys(set));
5060
+ const results = await Promise.all(Object.keys(set).map(async (contextName, index) => {
5061
+ const context = contexts.find((context2) => context2.id === contextName);
5062
+ if (!context) {
5063
+ console.error("[EXULU] Context not found for project information retrieval tool.", contextName);
5064
+ return [];
5065
+ }
5066
+ const itemIds = set[contextName];
5067
+ console.log("[EXULU] Project search tool searching through items", itemIds);
5068
+ return await context.search({
5069
+ // todo check if it is more performant to use a concatenation of
5070
+ // the query and keywords, or just the keywords, instead of the
5071
+ // query itself.
5072
+ query,
5073
+ filters: [{
5074
+ id: {
5075
+ in: itemIds
5076
+ }
5077
+ }],
5078
+ user,
5079
+ role,
5080
+ method: "hybridSearch",
5081
+ sort: {
5082
+ field: "updatedAt",
5083
+ direction: "desc"
5084
+ },
5085
+ trigger: "tool",
5086
+ limit: 10,
5087
+ page: 1
5088
+ });
5089
+ }));
5090
+ console.log("[EXULU] Project search tool results", results);
5091
+ return {
5092
+ result: JSON.stringify(results.flat())
5093
+ };
5094
+ }
5095
+ });
5096
+ return projectRetrievalTool;
5097
+ };
5098
+ var convertToolsArrayToObject = async (currentTools, allExuluTools, configs, providerapikey, contexts, user, exuluConfig, sessionID, req, project) => {
4953
5099
  if (!currentTools) return {};
4954
5100
  if (!allExuluTools) return {};
4955
5101
  if (!contexts) {
4956
5102
  contexts = [];
4957
5103
  }
5104
+ if (project) {
5105
+ const projectRetrievalTool = await createProjectRetrievalTool({
5106
+ user,
5107
+ role: user?.role?.id,
5108
+ contexts,
5109
+ projectId: project
5110
+ });
5111
+ if (projectRetrievalTool) {
5112
+ currentTools.push(projectRetrievalTool);
5113
+ }
5114
+ }
4958
5115
  const sanitizedTools = currentTools ? currentTools.map((tool2) => ({
4959
5116
  ...tool2,
4960
5117
  name: sanitizeToolName(tool2.name)
@@ -4963,9 +5120,9 @@ var convertToolsArrayToObject = (currentTools, allExuluTools, configs, providera
4963
5120
  return {
4964
5121
  ...sanitizedTools?.reduce(
4965
5122
  (prev, cur) => {
4966
- let config = configs?.find((config2) => config2.id === cur.id);
4967
- const userDefinedConfigDescription = config?.config.find((config2) => config2.name === "description")?.value;
4968
- const defaultConfigDescription = config?.config.find((config2) => config2.name === "description")?.default;
5123
+ let toolVariableConfig = configs?.find((config) => config.id === cur.id);
5124
+ const userDefinedConfigDescription = toolVariableConfig?.config.find((config) => config.name === "description")?.value;
5125
+ const defaultConfigDescription = toolVariableConfig?.config.find((config) => config.name === "description")?.default;
4969
5126
  const toolDescription = cur.description;
4970
5127
  const description = userDefinedConfigDescription || defaultConfigDescription || toolDescription;
4971
5128
  return {
@@ -4978,8 +5135,8 @@ var convertToolsArrayToObject = (currentTools, allExuluTools, configs, providera
4978
5135
  console.error("[EXULU] Tool execute function is undefined.", cur.tool);
4979
5136
  throw new Error("Tool execute function is undefined.");
4980
5137
  }
4981
- if (config) {
4982
- config = await hydrateVariables(config || []);
5138
+ if (toolVariableConfig) {
5139
+ toolVariableConfig = await hydrateVariables(toolVariableConfig || []);
4983
5140
  }
4984
5141
  let upload = void 0;
4985
5142
  if (exuluConfig?.fileUploads?.s3endpoint && exuluConfig?.fileUploads?.s3key && exuluConfig?.fileUploads?.s3secret && exuluConfig?.fileUploads?.s3Bucket) {
@@ -5032,7 +5189,6 @@ var convertToolsArrayToObject = (currentTools, allExuluTools, configs, providera
5032
5189
  acc[curr.id] = curr;
5033
5190
  return acc;
5034
5191
  }, {});
5035
- console.log("[EXULU] Config", config);
5036
5192
  const response = await cur.tool.execute({
5037
5193
  ...inputs,
5038
5194
  sessionID,
@@ -5047,7 +5203,7 @@ var convertToolsArrayToObject = (currentTools, allExuluTools, configs, providera
5047
5203
  contexts: contextsMap,
5048
5204
  upload,
5049
5205
  exuluConfig,
5050
- config: config ? config.config.reduce((acc, curr) => {
5206
+ toolVariablesConfig: toolVariableConfig ? toolVariableConfig.config.reduce((acc, curr) => {
5051
5207
  acc[curr.name] = curr.value;
5052
5208
  return acc;
5053
5209
  }, {}) : {}
@@ -5081,7 +5237,6 @@ var hydrateVariables = async (tool2) => {
5081
5237
  const variableName = toolConfig.variable;
5082
5238
  const variable = await db3.from("variables").where({ name: variableName }).first();
5083
5239
  if (!variable) {
5084
- console.error("[EXULU] Variable " + variableName + " not found.");
5085
5240
  throw new Error("Variable " + variableName + " not found.");
5086
5241
  }
5087
5242
  let value = variable.value;
@@ -5093,7 +5248,6 @@ var hydrateVariables = async (tool2) => {
5093
5248
  return toolConfig;
5094
5249
  });
5095
5250
  await Promise.all(promises);
5096
- console.log("[EXULU] Variable values retrieved and added to tool config.");
5097
5251
  return tool2;
5098
5252
  };
5099
5253
  function generateSlug(name) {
@@ -5317,7 +5471,21 @@ var ExuluAgent2 = class {
5317
5471
  });
5318
5472
  }
5319
5473
  console.log("[EXULU] Message count for agent: " + this.name, "loaded for generating sync.", messages.length);
5320
- const genericContext = "IMPORTANT: \n\n The current date is " + (/* @__PURE__ */ new Date()).toLocaleDateString() + " and the current time is " + (/* @__PURE__ */ new Date()).toLocaleTimeString() + ". If the user does not explicitly provide the current date, for examle when saying ' this weekend', you should assume they are talking with the current date in mind as a reference.";
5474
+ let project;
5475
+ if (session) {
5476
+ const sessionData = await getSession({ sessionID: session });
5477
+ project = sessionData.project;
5478
+ }
5479
+ const personalizationInformation = exuluConfig?.privacy?.systemPromptPersonalization !== false ? `
5480
+ ${user?.firstname ? `The users first name is "${user.firstname}"` : ""}
5481
+ ${user?.lastname ? `The users last name is "${user.lastname}"` : ""}
5482
+ ${user?.email ? `The users email is "${user.email}"` : ""}
5483
+ ` : "";
5484
+ const genericContext = `IMPORTANT general information:
5485
+ ${personalizationInformation}
5486
+ The current date is "${(/* @__PURE__ */ new Date()).toLocaleDateString()}" and the current time is "${(/* @__PURE__ */ new Date()).toLocaleTimeString()}".
5487
+ If the user does not explicitly provide the current date, for examle when saying ' this weekend', you should assume
5488
+ they are talking with the current date in mind as a reference.`;
5321
5489
  let system = instructions || "You are a helpful assistant. When you use a tool to answer a question do not explicitly comment on the result of the tool call unless the user has explicitly you to do something with the result.";
5322
5490
  system += "\n\n" + genericContext;
5323
5491
  if (prompt) {
@@ -5342,7 +5510,7 @@ var ExuluAgent2 = class {
5342
5510
  system,
5343
5511
  prompt,
5344
5512
  maxRetries: 2,
5345
- tools: convertToolsArrayToObject(
5513
+ tools: await convertToolsArrayToObject(
5346
5514
  currentTools,
5347
5515
  allExuluTools,
5348
5516
  toolConfigs,
@@ -5351,7 +5519,8 @@ var ExuluAgent2 = class {
5351
5519
  user,
5352
5520
  exuluConfig,
5353
5521
  session,
5354
- req
5522
+ req,
5523
+ project
5355
5524
  ),
5356
5525
  stopWhen: [stepCountIs(2)]
5357
5526
  });
@@ -5402,7 +5571,7 @@ var ExuluAgent2 = class {
5402
5571
  ignoreIncompleteToolCalls: true
5403
5572
  }),
5404
5573
  maxRetries: 2,
5405
- tools: convertToolsArrayToObject(
5574
+ tools: await convertToolsArrayToObject(
5406
5575
  currentTools,
5407
5576
  allExuluTools,
5408
5577
  toolConfigs,
@@ -5411,7 +5580,8 @@ var ExuluAgent2 = class {
5411
5580
  user,
5412
5581
  exuluConfig,
5413
5582
  session,
5414
- req
5583
+ req,
5584
+ project
5415
5585
  ),
5416
5586
  stopWhen: [stepCountIs(2)]
5417
5587
  });
@@ -5461,7 +5631,6 @@ var ExuluAgent2 = class {
5461
5631
  */
5462
5632
  async processFilePartsInMessages(messages) {
5463
5633
  const processedMessages = await Promise.all(messages.map(async (message) => {
5464
- console.log("[EXULU] Processing file parts in messages: " + JSON.stringify(message, null, 2));
5465
5634
  if (message.role !== "user" || !Array.isArray(message.parts)) {
5466
5635
  return message;
5467
5636
  }
@@ -5472,7 +5641,7 @@ var ExuluAgent2 = class {
5472
5641
  const { mediaType, url, filename } = part;
5473
5642
  const imageTypes = ["image/png", "image/jpeg", "image/jpg", "image/gif", "image/webp"];
5474
5643
  if (imageTypes.includes(mediaType)) {
5475
- console.log(`[EXULU] Converting file part to image part: ${filename}`);
5644
+ console.log(`[EXULU] Converting file part to image part: ${filename} `);
5476
5645
  return {
5477
5646
  type: "image",
5478
5647
  image: url,
@@ -5483,7 +5652,7 @@ var ExuluAgent2 = class {
5483
5652
  try {
5484
5653
  const response = await fetch(url);
5485
5654
  if (!response.ok) {
5486
- console.error(`[EXULU] Failed to fetch file: ${filename}, status: ${response.status}`);
5655
+ console.error(`[EXULU] Failed to fetch file: ${filename}, status: ${response.status} `);
5487
5656
  return {
5488
5657
  type: "text",
5489
5658
  text: `[Error: Could not load file ${filename}]`
@@ -5496,9 +5665,9 @@ var ExuluAgent2 = class {
5496
5665
  });
5497
5666
  return {
5498
5667
  type: "text",
5499
- text: `<file name="${filename}">
5500
- ${extractedText}
5501
- </file>`
5668
+ text: `<file file name = "${filename}" >
5669
+ ${extractedText}
5670
+ </file>`
5502
5671
  };
5503
5672
  } catch (error) {
5504
5673
  console.error(`[EXULU] Error processing file ${filename}:`, error);
@@ -5548,7 +5717,10 @@ ${extractedText}
5548
5717
  });
5549
5718
  let messages = [];
5550
5719
  let previousMessagesContent = previousMessages || [];
5720
+ let project;
5551
5721
  if (session) {
5722
+ const sessionData = await getSession({ sessionID: session });
5723
+ project = sessionData.project;
5552
5724
  console.log("[EXULU] loading previous messages from session: " + session);
5553
5725
  const previousMessages2 = await getAgentMessages({
5554
5726
  session,
@@ -5567,20 +5739,18 @@ ${extractedText}
5567
5739
  messages = messages.filter(
5568
5740
  (message2, index, self) => index === self.findIndex((t) => t.id === message2.id)
5569
5741
  );
5570
- console.log("[EXULU] Processing file parts in messages for OpenAI Responses API compatibility");
5571
5742
  messages = await this.processFilePartsInMessages(messages);
5572
5743
  const genericContext = "IMPORTANT: \n\n The current date is " + (/* @__PURE__ */ new Date()).toLocaleDateString() + " and the current time is " + (/* @__PURE__ */ new Date()).toLocaleTimeString() + ". If the user does not explicitly provide the current date, for examle when saying ' this weekend', you should assume they are talking with the current date in mind as a reference.";
5573
5744
  let system = instructions || "You are a helpful assistant. When you use a tool to answer a question do not explicitly comment on the result of the tool call unless the user has explicitly you to do something with the result.";
5574
5745
  system += "\n\n" + genericContext;
5575
- console.log("[EXULU] tools for agent: " + this.name, currentTools?.map((x) => x.name + " (" + x.id + ")"));
5576
- console.log("[EXULU] system", system.slice(0, 100) + "...");
5577
5746
  const result = streamText({
5578
5747
  model,
5579
5748
  // Should be a LanguageModelV1
5580
5749
  messages: convertToModelMessages(messages, {
5581
5750
  ignoreIncompleteToolCalls: true
5582
5751
  }),
5583
- // prepareStep could be used here to set the model for the first step or change other params
5752
+ // PrepareStep could be used here to set the model
5753
+ // for the first step or change other parameters.
5584
5754
  system,
5585
5755
  maxRetries: 2,
5586
5756
  providerOptions: {
@@ -5588,7 +5758,7 @@ ${extractedText}
5588
5758
  reasoningSummary: "auto"
5589
5759
  }
5590
5760
  },
5591
- tools: convertToolsArrayToObject(
5761
+ tools: await convertToolsArrayToObject(
5592
5762
  currentTools,
5593
5763
  allExuluTools,
5594
5764
  toolConfigs,
@@ -5597,7 +5767,8 @@ ${extractedText}
5597
5767
  user,
5598
5768
  exuluConfig,
5599
5769
  session,
5600
- req
5770
+ req,
5771
+ project
5601
5772
  ),
5602
5773
  onError: (error) => {
5603
5774
  console.error("[EXULU] chat stream error.", error);
@@ -5693,12 +5864,10 @@ var ExuluEmbedder = class {
5693
5864
  id
5694
5865
  } = setting;
5695
5866
  let value = "";
5696
- console.log("[EXULU] variable name", variableName);
5697
5867
  const variable = await db3.from("variables").where({ name: variableName }).first();
5698
5868
  if (!variable) {
5699
5869
  throw new Error("Variable not found for embedder setting: " + name + " in context: " + context + " and embedder: " + this.id);
5700
5870
  }
5701
- console.log("[EXULU] variable", variable);
5702
5871
  if (variable.encrypted) {
5703
5872
  if (!process.env.NEXTAUTH_SECRET) {
5704
5873
  throw new Error("NEXTAUTH_SECRET environment variable is not set, cannot decrypt variable: " + name);
@@ -5710,14 +5879,12 @@ var ExuluEmbedder = class {
5710
5879
  throw new Error("Decryption returned empty string - invalid key or corrupted data");
5711
5880
  }
5712
5881
  value = decrypted;
5713
- console.log("[EXULU] successfully decrypted value for", name);
5714
5882
  } catch (error) {
5715
5883
  throw new Error(`Failed to decrypt variable "${name}" for embedder setting in context "${context}": ${error instanceof Error ? error.message : "Unknown error"}. Verify that NEXTAUTH_SECRET matches the key used during encryption.`);
5716
5884
  }
5717
5885
  } else {
5718
5886
  value = variable.value;
5719
5887
  }
5720
- console.log("[EXULU] variable value", value);
5721
5888
  hydrated.push({
5722
5889
  id: id || "",
5723
5890
  name,
@@ -5825,14 +5992,20 @@ var ExuluStorage = class {
5825
5992
  getPresignedUrl = async (key) => {
5826
5993
  return await getPresignedUrl(key, this.config);
5827
5994
  };
5828
- uploadFile = async (user, file, key, type, metadata) => {
5829
- return await uploadFile(user, file, key, this.config, {
5830
- contentType: type,
5831
- metadata: {
5832
- ...metadata,
5833
- type
5834
- }
5835
- });
5995
+ uploadFile = async (file, key, type, user, metadata) => {
5996
+ return await uploadFile(
5997
+ file,
5998
+ key,
5999
+ this.config,
6000
+ {
6001
+ contentType: type,
6002
+ metadata: {
6003
+ ...metadata,
6004
+ type
6005
+ }
6006
+ },
6007
+ user
6008
+ );
5836
6009
  };
5837
6010
  // todo add upload and delete methods
5838
6011
  };
@@ -5852,7 +6025,19 @@ var ExuluContext = class {
5852
6025
  // todo typings
5853
6026
  configuration;
5854
6027
  sources = [];
5855
- constructor({ id, name, description, embedder, active, rateLimit, fields, queryRewriter, resultReranker, configuration, sources }) {
6028
+ constructor({
6029
+ id,
6030
+ name,
6031
+ description,
6032
+ embedder,
6033
+ active,
6034
+ rateLimit,
6035
+ fields,
6036
+ queryRewriter,
6037
+ resultReranker,
6038
+ configuration,
6039
+ sources
6040
+ }) {
5856
6041
  this.id = id;
5857
6042
  this.name = name;
5858
6043
  this.fields = fields || [];
@@ -5869,7 +6054,7 @@ var ExuluContext = class {
5869
6054
  this.queryRewriter = queryRewriter;
5870
6055
  this.resultReranker = resultReranker;
5871
6056
  }
5872
- processField = async (trigger, user, role, item, config) => {
6057
+ processField = async (trigger, item, exuluConfig, user, role) => {
5873
6058
  console.log("[EXULU] processing field", item.field, " in context", this.id);
5874
6059
  console.log("[EXULU] fields", this.fields.map((field2) => field2.name));
5875
6060
  const field = this.fields.find((field2) => {
@@ -5879,7 +6064,7 @@ var ExuluContext = class {
5879
6064
  console.error("[EXULU] field not found or processor not set for field", item.field, " in context", this.id);
5880
6065
  throw new Error("Field not found or processor not set for field " + item.field + " in context " + this.id);
5881
6066
  }
5882
- const exuluStorage = new ExuluStorage({ config });
6067
+ const exuluStorage = new ExuluStorage({ config: exuluConfig });
5883
6068
  const queue = await field.processor.config?.queue;
5884
6069
  if (queue?.queue.name) {
5885
6070
  console.log("[EXULU] processor is in queue mode, scheduling job.");
@@ -5905,6 +6090,7 @@ var ExuluContext = class {
5905
6090
  job: job.id
5906
6091
  };
5907
6092
  }
6093
+ console.log("[EXULU] POS 1 -- EXULU CONTEXT PROCESS FIELD");
5908
6094
  const result = await field.processor.execute({
5909
6095
  item,
5910
6096
  user,
@@ -5917,13 +6103,24 @@ var ExuluContext = class {
5917
6103
  delete: this.deleteItem
5918
6104
  }
5919
6105
  },
5920
- config
6106
+ exuluConfig
5921
6107
  });
5922
6108
  return {
5923
6109
  result,
5924
6110
  job: void 0
5925
6111
  };
5926
6112
  };
6113
+ search = async (options) => {
6114
+ const { db: db3 } = await postgresClient();
6115
+ const result = await vectorSearch({
6116
+ ...options,
6117
+ user: options.user,
6118
+ role: options.role,
6119
+ context: this,
6120
+ db: db3
6121
+ });
6122
+ return result;
6123
+ };
5927
6124
  deleteAll = async () => {
5928
6125
  const { db: db3 } = await postgresClient();
5929
6126
  await db3.from(getTableName(this.id)).delete();
@@ -5933,8 +6130,11 @@ var ExuluContext = class {
5933
6130
  results: []
5934
6131
  };
5935
6132
  };
5936
- executeSource = async (source, inputs) => {
5937
- return await source.execute(inputs);
6133
+ executeSource = async (source, inputs, exuluConfig) => {
6134
+ return await source.execute({
6135
+ ...inputs,
6136
+ exuluConfig
6137
+ });
5938
6138
  };
5939
6139
  tableExists = async () => {
5940
6140
  const { db: db3 } = await postgresClient();
@@ -5990,7 +6190,7 @@ var ExuluContext = class {
5990
6190
  job
5991
6191
  };
5992
6192
  };
5993
- createItem = async (item, config, user, role, upsert) => {
6193
+ createItem = async (item, config, user, role, upsert, generateEmbeddingsOverwrite) => {
5994
6194
  if (upsert && (!item.id && !item.external_id)) {
5995
6195
  throw new Error("Item id or external id is required for upsert.");
5996
6196
  }
@@ -6017,12 +6217,40 @@ var ExuluContext = class {
6017
6217
  throw new Error("Failed to create item.");
6018
6218
  }
6019
6219
  console.log("[EXULU] context configuration", this.configuration);
6020
- if (this.embedder && (this.configuration.calculateVectors === "onUpdate" || this.configuration.calculateVectors === "always")) {
6220
+ let jobs = [];
6221
+ let shouldGenerateEmbeddings = this.embedder && generateEmbeddingsOverwrite !== false && (generateEmbeddingsOverwrite || this.configuration.calculateVectors === "onUpdate" || this.configuration.calculateVectors === "onInsert" || this.configuration.calculateVectors === "always");
6222
+ for (const [key, value] of Object.entries(item)) {
6223
+ console.log("[EXULU] Checking for processors for field", key);
6224
+ const processor = this.fields.find((field) => field.name === key.replace("_s3key", ""))?.processor;
6225
+ console.log("[EXULU] Processor found", processor);
6226
+ if (processor && (processor?.config?.trigger === "onInsert" || processor?.config?.trigger === "onUpdate" || processor?.config?.trigger === "always")) {
6227
+ const {
6228
+ job: processorJob,
6229
+ result: processorResult
6230
+ } = await this.processField(
6231
+ "api",
6232
+ {
6233
+ ...item,
6234
+ id: results[0].id,
6235
+ field: key
6236
+ },
6237
+ config,
6238
+ user,
6239
+ role
6240
+ );
6241
+ if (processorJob) {
6242
+ jobs.push(processorJob);
6243
+ }
6244
+ if (!processorJob && processor.config?.generateEmbeddings) {
6245
+ shouldGenerateEmbeddings = true;
6246
+ }
6247
+ }
6248
+ }
6249
+ if (shouldGenerateEmbeddings) {
6021
6250
  console.log("[EXULU] generating embeddings for item", results[0].id);
6022
- const { job } = await this.embeddings.generate.one({
6251
+ const { job: embeddingsJob } = await this.embeddings.generate.one({
6023
6252
  item: {
6024
6253
  ...item,
6025
- // important we need to full record here with all fields for the embedder
6026
6254
  id: results[0].id
6027
6255
  },
6028
6256
  user,
@@ -6030,17 +6258,16 @@ var ExuluContext = class {
6030
6258
  trigger: "api",
6031
6259
  config
6032
6260
  });
6033
- return {
6034
- item: results[0],
6035
- job
6036
- };
6261
+ if (embeddingsJob) {
6262
+ jobs.push(embeddingsJob);
6263
+ }
6037
6264
  }
6038
6265
  return {
6039
6266
  item: results[0],
6040
- job: void 0
6267
+ job: jobs.length > 0 ? jobs.join(",") : void 0
6041
6268
  };
6042
6269
  };
6043
- updateItem = async (item, config, user, role) => {
6270
+ updateItem = async (item, config, user, role, generateEmbeddingsOverwrite) => {
6044
6271
  const { db: db3 } = await postgresClient();
6045
6272
  if (item.field) {
6046
6273
  delete item.field;
@@ -6064,8 +6291,35 @@ var ExuluContext = class {
6064
6291
  }
6065
6292
  ).returning("id");
6066
6293
  await mutation;
6067
- if (this.embedder && (this.configuration.calculateVectors === "onUpdate" || this.configuration.calculateVectors === "always")) {
6068
- const { job } = await this.embeddings.generate.one({
6294
+ let jobs = [];
6295
+ let shouldGenerateEmbeddings = this.embedder && generateEmbeddingsOverwrite !== false && (generateEmbeddingsOverwrite || this.configuration.calculateVectors === "onUpdate" || this.configuration.calculateVectors === "always");
6296
+ for (const [key, value] of Object.entries(item)) {
6297
+ const processor = this.fields.find((field) => field.name === key.replace("_s3key", ""))?.processor;
6298
+ if (processor && (processor?.config?.trigger === "onInsert" || processor?.config?.trigger === "onUpdate" || processor?.config?.trigger === "always")) {
6299
+ const {
6300
+ job: processorJob,
6301
+ result: processorResult
6302
+ } = await this.processField(
6303
+ "api",
6304
+ {
6305
+ ...item,
6306
+ id: record.id,
6307
+ field: key
6308
+ },
6309
+ config,
6310
+ user,
6311
+ role
6312
+ );
6313
+ if (processorJob) {
6314
+ jobs.push(processorJob);
6315
+ }
6316
+ if (!processorJob && processor.config?.generateEmbeddings) {
6317
+ shouldGenerateEmbeddings = true;
6318
+ }
6319
+ }
6320
+ }
6321
+ if (shouldGenerateEmbeddings) {
6322
+ const { job: embeddingsJob } = await this.embeddings.generate.one({
6069
6323
  item: record,
6070
6324
  // important we need to full record here with all fields for the embedder
6071
6325
  user,
@@ -6073,14 +6327,13 @@ var ExuluContext = class {
6073
6327
  trigger: "api",
6074
6328
  config
6075
6329
  });
6076
- return {
6077
- item: record,
6078
- job
6079
- };
6330
+ if (embeddingsJob) {
6331
+ jobs.push(embeddingsJob);
6332
+ }
6080
6333
  }
6081
6334
  return {
6082
6335
  item: record,
6083
- job: void 0
6336
+ job: jobs.length > 0 ? jobs.join(",") : void 0
6084
6337
  };
6085
6338
  };
6086
6339
  deleteItem = async (item, user, role) => {
@@ -6107,6 +6360,34 @@ var ExuluContext = class {
6107
6360
  job: void 0
6108
6361
  };
6109
6362
  };
6363
+ getItem = async ({ item }) => {
6364
+ const { db: db3 } = await postgresClient();
6365
+ if (!item.id && !item.external_id) {
6366
+ throw new Error("Item id or external id is required to get an item.");
6367
+ }
6368
+ const result = await db3.from(getTableName(this.id)).where({
6369
+ ...item.id ? { id: item.id } : {},
6370
+ ...item.external_id ? { external_id: item.external_id } : {}
6371
+ }).first();
6372
+ if (result) {
6373
+ const chunksCount = await db3.from(getChunksTableName(this.id)).where(
6374
+ { source: result.id }
6375
+ ).count("id");
6376
+ result.chunksCount = Number(chunksCount[0].count) || 0;
6377
+ }
6378
+ return result;
6379
+ };
6380
+ getItems = async ({
6381
+ filters,
6382
+ fields
6383
+ }) => {
6384
+ const { db: db3 } = await postgresClient();
6385
+ let query = db3.from(getTableName(this.id)).select(fields || "*");
6386
+ const tableDefinition = contextToTableDefinition(this);
6387
+ query = applyFilters(query, filters || [], tableDefinition);
6388
+ const items = await query;
6389
+ return items;
6390
+ };
6110
6391
  embeddings = {
6111
6392
  generate: {
6112
6393
  one: async ({
@@ -6123,6 +6404,12 @@ var ExuluContext = class {
6123
6404
  if (!item.id) {
6124
6405
  throw new Error("Item id is required for generating embeddings.");
6125
6406
  }
6407
+ const { db: db3 } = await postgresClient();
6408
+ const record = await db3.from(getTableName(this.id)).where({ id: item.id }).first();
6409
+ if (!record) {
6410
+ throw new Error("Item not found.");
6411
+ }
6412
+ item = record;
6126
6413
  const queue = await this.embedder.queue;
6127
6414
  if (queue?.queue.name) {
6128
6415
  console.log("[EXULU] embedder is in queue mode, scheduling job.");
@@ -6888,7 +7175,7 @@ Mood: friendly and intelligent.
6888
7175
  const user = authenticationResult.user;
6889
7176
  let agentQuery = db3("agents");
6890
7177
  agentQuery.select("*");
6891
- agentQuery = applyAccessControl(agentsSchema2(), authenticationResult.user, agentQuery);
7178
+ agentQuery = applyAccessControl(agentsSchema2(), agentQuery, authenticationResult.user);
6892
7179
  agentQuery.where({ id: req.params.agent });
6893
7180
  const agent = await agentQuery.first();
6894
7181
  if (!agent) {
@@ -6905,7 +7192,7 @@ Mood: friendly and intelligent.
6905
7192
  } else {
6906
7193
  let projectQuery = db3("projects");
6907
7194
  projectQuery.select("*");
6908
- projectQuery = applyAccessControl(projectsSchema2(), authenticationResult.user, projectQuery);
7195
+ projectQuery = applyAccessControl(projectsSchema2(), projectQuery, authenticationResult.user);
6909
7196
  projectQuery.where({ id: req.params.project });
6910
7197
  project = await projectQuery.first();
6911
7198
  if (!project) {
@@ -7247,6 +7534,7 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
7247
7534
  if (!data.role) {
7248
7535
  throw new Error(`Role not set for processor job.`);
7249
7536
  }
7537
+ console.log("[EXULU] POS 2 -- EXULU CONTEXT PROCESS FIELD");
7250
7538
  const result = await field.processor.execute({
7251
7539
  item: data.inputs,
7252
7540
  user: data.user,
@@ -7261,9 +7549,24 @@ var createWorkers = async (agents, queues2, config, contexts, evals, tools, trac
7261
7549
  },
7262
7550
  config
7263
7551
  });
7552
+ let jobs = [];
7553
+ if (field.processor.config?.generateEmbeddings) {
7554
+ const { job: embeddingsJob } = await context.embeddings.generate.one({
7555
+ item: data.inputs,
7556
+ user: data.user,
7557
+ role: data.role,
7558
+ trigger: "api",
7559
+ config
7560
+ });
7561
+ if (embeddingsJob) {
7562
+ jobs.push(embeddingsJob);
7563
+ }
7564
+ }
7264
7565
  return {
7265
7566
  result,
7266
- metadata: {}
7567
+ metadata: {
7568
+ jobs: jobs.length > 0 ? jobs.join(",") : void 0
7569
+ }
7267
7570
  };
7268
7571
  }
7269
7572
  if (data.type === "eval_run") {
@@ -7949,7 +8252,7 @@ var ExuluMCP = class {
7949
8252
  console.log("[EXULU] MCP tool inputs", inputs);
7950
8253
  console.log("[EXULU] MCP tool args", args);
7951
8254
  const configValues = agentInstance.tools;
7952
- const tools = convertToolsArrayToObject(
8255
+ const tools = await convertToolsArrayToObject(
7953
8256
  [tool2],
7954
8257
  allTools,
7955
8258
  configValues,