@exulu/backend 1.6.1 → 1.7.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.cjs CHANGED
@@ -304,41 +304,50 @@ var bullmqDecorator = async ({
304
304
  };
305
305
 
306
306
  // src/registry/utils/map-types.ts
307
- var mapType = (t, type, name, defaultValue) => {
307
+ var mapType = (t, type, name, defaultValue, unique) => {
308
308
  if (type === "text") {
309
309
  t.text(name);
310
+ if (unique) t.unique(name);
310
311
  return;
311
312
  }
312
313
  if (type === "longText") {
313
314
  t.text(name);
315
+ if (unique) t.unique(name);
314
316
  return;
315
317
  }
316
318
  if (type === "shortText") {
317
319
  t.string(name, 100);
320
+ if (unique) t.unique(name);
318
321
  return;
319
322
  }
320
323
  if (type === "number") {
321
324
  t.float(name);
325
+ if (unique) t.unique(name);
322
326
  return;
323
327
  }
324
328
  if (type === "boolean") {
325
329
  t.boolean(name).defaultTo(defaultValue || false);
330
+ if (unique) t.unique(name);
326
331
  return;
327
332
  }
328
333
  if (type === "code") {
329
334
  t.text(name);
335
+ if (unique) t.unique(name);
330
336
  return;
331
337
  }
332
338
  if (type === "json") {
333
339
  t.jsonb(name);
340
+ if (unique) t.unique(name);
334
341
  return;
335
342
  }
336
343
  if (type === "date") {
337
344
  t.timestamp(name);
345
+ if (unique) t.unique(name);
338
346
  return;
339
347
  }
340
348
  if (type === "uuid") {
341
349
  t.uuid(name);
350
+ if (unique) t.unique(name);
342
351
  return;
343
352
  }
344
353
  throw new Error("Invalid type: " + type);
@@ -437,7 +446,39 @@ var ExuluEvalUtils = {
437
446
  }
438
447
  };
439
448
 
449
+ // src/registry/utils/claude-messages.ts
450
+ var CLAUDE_MESSAGES = {
451
+ anthropic_token_variable_not_encrypted: `
452
+ \x1B[41m -- Anthropic token variable set by your admin is not encrypted. This poses a security risk. Please contact your admin to fix the variable used for your key. --
453
+ \x1B[0m`,
454
+ anthropic_token_variable_not_found: `
455
+ \x1B[41m -- Anthropic token variable not found. Please contact to fix the variable used for your key. --
456
+ \x1B[0m`,
457
+ authentication_error: `
458
+ \x1B[41m -- Authentication error please check your IMP token and try again. --
459
+ \x1B[0m`,
460
+ missing_body: `
461
+ \x1B[41m -- Missing body Anthropic response. --
462
+ \x1B[0m`,
463
+ missing_nextauth_secret: `
464
+ \x1B[41m -- Missing NEXTAUTH_SECRET in environment variables on the server. --
465
+ \x1B[0m`,
466
+ not_enabled: `
467
+ \x1B[31m
468
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557
469
+ \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2588\u2588\u2557\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
470
+ \u2588\u2588\u2588\u2588\u2588\u2557 \u255A\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
471
+ \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
472
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2554\u255D \u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
473
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D
474
+ Intelligence Management Platform
475
+ \x1B[0m
476
+ \x1B[41m -- Your account has not been enabled to use Claude Code, please contact your admin or enable Claude Code in the user settings. --
477
+ \x1B[0m`
478
+ };
479
+
440
480
  // src/registry/classes.ts
481
+ var import_crypto_js = __toESM(require("crypto-js"), 1);
441
482
  function sanitizeToolName(name) {
442
483
  if (typeof name !== "string") return "";
443
484
  let sanitized = name.replace(/[^a-zA-Z0-9_-]+/g, "_");
@@ -447,7 +488,7 @@ function sanitizeToolName(name) {
447
488
  }
448
489
  return sanitized;
449
490
  }
450
- var convertToolsArrayToObject = (tools) => {
491
+ var convertToolsArrayToObject = (tools, configs) => {
451
492
  if (!tools) return {};
452
493
  const sanitizedTools = tools ? tools.map((tool2) => ({
453
494
  ...tool2,
@@ -461,12 +502,57 @@ var convertToolsArrayToObject = (tools) => {
461
502
  };
462
503
  return {
463
504
  ...sanitizedTools?.reduce(
464
- (prev, cur) => ({ ...prev, [cur.name]: cur.tool }),
505
+ (prev, cur) => ({
506
+ ...prev,
507
+ [cur.name]: {
508
+ ...cur.tool,
509
+ execute: async (inputs, options) => {
510
+ if (!cur.tool?.execute) {
511
+ console.error("[EXULU] Tool execute function is undefined.", cur.tool);
512
+ throw new Error("Tool execute function is undefined.");
513
+ }
514
+ let config = configs?.find((config2) => config2.toolId === cur.id);
515
+ if (config) {
516
+ config = await hydrateVariables(config || []);
517
+ }
518
+ return await cur.tool.execute({
519
+ ...inputs,
520
+ // Convert config to object format if a config object
521
+ // is available, after we added the .value property
522
+ // by hydrating it from the variables table.
523
+ config: config ? config.config.reduce((acc, curr) => {
524
+ acc[curr.name] = curr.value;
525
+ return acc;
526
+ }, {}) : {}
527
+ }, options);
528
+ }
529
+ }
530
+ }),
465
531
  {}
466
532
  ),
467
533
  askForConfirmation
468
534
  };
469
535
  };
536
+ var hydrateVariables = async (tool2) => {
537
+ const { db: db3 } = await postgresClient();
538
+ const promises2 = tool2.config.map(async (toolConfig) => {
539
+ const variableName = toolConfig.variable;
540
+ const variable = await db3.from("variables").where({ name: variableName }).first();
541
+ if (!variable) {
542
+ console.error("[EXULU] Variable " + variableName + " not found.");
543
+ throw new Error("Variable " + variableName + " not found.");
544
+ }
545
+ let value = variable.value;
546
+ if (variable.encrypted) {
547
+ const bytes = import_crypto_js.default.AES.decrypt(variable.value, process.env.NEXTAUTH_SECRET);
548
+ value = bytes.toString(import_crypto_js.default.enc.Utf8);
549
+ }
550
+ toolConfig.value = value;
551
+ });
552
+ await Promise.all(promises2);
553
+ console.log("[EXULU] Variable values retrieved and added to tool config.");
554
+ return tool2;
555
+ };
470
556
  function generateSlug(name) {
471
557
  const normalized = name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "");
472
558
  const lowercase = normalized.toLowerCase();
@@ -523,12 +609,13 @@ var ExuluAgent = class {
523
609
  tool = () => {
524
610
  return new ExuluTool({
525
611
  id: this.id,
526
- name: `${this.name} agent`,
612
+ name: `${this.name}`,
527
613
  type: "agent",
528
614
  inputSchema: import_zod2.z.object({
529
615
  prompt: import_zod2.z.string()
530
616
  }),
531
617
  description: `A function that calls an AI agent named: ${this.name}. The agent does the following: ${this.description}.`,
618
+ config: [],
532
619
  execute: async ({ prompt }) => {
533
620
  return await this.generateSync({
534
621
  prompt,
@@ -540,7 +627,7 @@ var ExuluAgent = class {
540
627
  }
541
628
  });
542
629
  };
543
- generateSync = async ({ messages, prompt, tools, statistics }) => {
630
+ generateSync = async ({ messages, prompt, tools, statistics, configs }) => {
544
631
  if (!this.model) {
545
632
  throw new Error("Model is required for streaming.");
546
633
  }
@@ -556,7 +643,7 @@ var ExuluAgent = class {
556
643
  messages,
557
644
  prompt,
558
645
  maxRetries: 2,
559
- tools: convertToolsArrayToObject(tools),
646
+ tools: convertToolsArrayToObject(tools, configs),
560
647
  maxSteps: 5
561
648
  });
562
649
  if (statistics) {
@@ -570,7 +657,7 @@ var ExuluAgent = class {
570
657
  }
571
658
  return text;
572
659
  };
573
- generateStream = ({ messages, prompt, tools, statistics }) => {
660
+ generateStream = ({ messages, prompt, tools, statistics, configs }) => {
574
661
  if (!this.model) {
575
662
  throw new Error("Model is required for streaming.");
576
663
  }
@@ -586,7 +673,7 @@ var ExuluAgent = class {
586
673
  prompt,
587
674
  system: "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.",
588
675
  maxRetries: 2,
589
- tools: convertToolsArrayToObject(tools),
676
+ tools: convertToolsArrayToObject(tools, configs),
590
677
  maxSteps: 5,
591
678
  onError: (error) => console.error("[EXULU] chat stream error.", error),
592
679
  onFinish: async ({ response, usage }) => {
@@ -942,8 +1029,10 @@ var ExuluTool = class {
942
1029
  inputSchema;
943
1030
  type;
944
1031
  tool;
945
- constructor({ id, name, description, inputSchema, type, execute: execute2 }) {
1032
+ config;
1033
+ constructor({ id, name, description, inputSchema, type, execute: execute2, config }) {
946
1034
  this.id = id;
1035
+ this.config = config;
947
1036
  this.name = name;
948
1037
  this.description = description;
949
1038
  this.inputSchema = inputSchema;
@@ -1351,11 +1440,11 @@ var ExuluContext = class {
1351
1440
  table.text("source");
1352
1441
  table.timestamp("embeddings_updated_at");
1353
1442
  for (const field of this.fields) {
1354
- const { type, name } = field;
1443
+ const { type, name, unique } = field;
1355
1444
  if (!type || !name) {
1356
1445
  continue;
1357
1446
  }
1358
- mapType(table, type, sanitizeName(name));
1447
+ mapType(table, type, sanitizeName(name), void 0, unique);
1359
1448
  }
1360
1449
  table.timestamps(true, true);
1361
1450
  });
@@ -1377,11 +1466,12 @@ var ExuluContext = class {
1377
1466
  tool = () => {
1378
1467
  return new ExuluTool({
1379
1468
  id: this.id,
1380
- name: `${this.name} context`,
1469
+ name: `${this.name}`,
1381
1470
  type: "context",
1382
1471
  inputSchema: import_zod2.z.object({
1383
1472
  query: import_zod2.z.string()
1384
1473
  }),
1474
+ config: [],
1385
1475
  description: `Gets information from the context called: ${this.name}. The context description is: ${this.description}.`,
1386
1476
  execute: async ({ query }) => {
1387
1477
  return await this.getItems({
@@ -1849,7 +1939,7 @@ var import_reflect_metadata = require("reflect-metadata");
1849
1939
  var import_schema = require("@graphql-tools/schema");
1850
1940
  var import_graphql_type_json = __toESM(require("graphql-type-json"), 1);
1851
1941
  var import_graphql = require("graphql");
1852
- var import_crypto_js = __toESM(require("crypto-js"), 1);
1942
+ var import_crypto_js2 = __toESM(require("crypto-js"), 1);
1853
1943
  var GraphQLDate = new import_graphql.GraphQLScalarType({
1854
1944
  name: "Date",
1855
1945
  description: "Date custom scalar type",
@@ -2015,8 +2105,9 @@ function createMutations(table) {
2015
2105
  return results[0];
2016
2106
  },
2017
2107
  [`${tableNamePlural}UpdateOne`]: async (_, args, context, info) => {
2018
- const { db: db3 } = context;
2108
+ const { db: db3, req } = context;
2019
2109
  let { where, input } = args;
2110
+ await validateSuperAdminPermission(tableNamePlural, input, req);
2020
2111
  input = encryptSensitiveFields(input);
2021
2112
  await db3(tableNamePlural).where(where).update({
2022
2113
  ...input,
@@ -2027,9 +2118,10 @@ function createMutations(table) {
2027
2118
  return result;
2028
2119
  },
2029
2120
  [`${tableNamePlural}UpdateOneById`]: async (_, args, context, info) => {
2121
+ const { db: db3, req } = context;
2030
2122
  let { id, input } = args;
2123
+ await validateSuperAdminPermission(tableNamePlural, input, req);
2031
2124
  input = encryptSensitiveFields(input);
2032
- const { db: db3 } = context;
2033
2125
  await db3(tableNamePlural).where({ id }).update({
2034
2126
  ...input,
2035
2127
  updatedAt: /* @__PURE__ */ new Date()
@@ -2166,6 +2258,7 @@ function createQueries(table) {
2166
2258
  };
2167
2259
  }
2168
2260
  function createSDL(tables) {
2261
+ console.log("[EXULU] Creating SDL");
2169
2262
  let typeDefs = `
2170
2263
  scalar JSON
2171
2264
  scalar Date
@@ -2181,6 +2274,7 @@ function createSDL(tables) {
2181
2274
  const tableNamePlural = table.name.plural.toLowerCase();
2182
2275
  const tableNameSingular = table.name.singular.toLowerCase();
2183
2276
  const tableNameSingularUpperCaseFirst = table.name.singular.charAt(0).toUpperCase() + table.name.singular.slice(1);
2277
+ console.log("[EXULU] Adding table >>>>>", tableNamePlural);
2184
2278
  typeDefs += `
2185
2279
  ${tableNameSingular}ById(id: ID!): ${tableNameSingular}
2186
2280
  ${tableNamePlural}Pagination(limit: Int, page: Int, filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingularUpperCaseFirst}PaginationResult
@@ -2255,15 +2349,23 @@ type JobStatistics {
2255
2349
  console.log("\n");
2256
2350
  return schema;
2257
2351
  }
2258
- var sensitiveFields = ["anthropic_token"];
2259
2352
  var encryptSensitiveFields = (input) => {
2260
- sensitiveFields.forEach((field) => {
2261
- if (input[field]) {
2262
- input[field] = import_crypto_js.default.AES.encrypt(input[field], process.env.NEXTAUTH_SECRET).toString();
2263
- }
2264
- });
2353
+ if (input.value && input.encrypted === true) {
2354
+ input.value = import_crypto_js2.default.AES.encrypt(input.value, process.env.NEXTAUTH_SECRET).toString();
2355
+ }
2265
2356
  return input;
2266
2357
  };
2358
+ var validateSuperAdminPermission = async (tableNamePlural, input, req) => {
2359
+ if (tableNamePlural === "users" && input.super_admin !== void 0) {
2360
+ const authResult = await requestValidators.authenticate(req);
2361
+ if (authResult.error || !authResult.user) {
2362
+ throw new Error("Authentication failed");
2363
+ }
2364
+ if (!authResult.user.super_admin) {
2365
+ throw new Error("Only super administrators can modify super_admin status");
2366
+ }
2367
+ }
2368
+ };
2267
2369
 
2268
2370
  // src/registry/routes.ts
2269
2371
  var import_express5 = require("@as-integrations/express5");
@@ -2601,6 +2703,29 @@ var agentsSchema = {
2601
2703
  }
2602
2704
  ]
2603
2705
  };
2706
+ var variablesSchema = {
2707
+ name: {
2708
+ plural: "variables",
2709
+ singular: "variable"
2710
+ },
2711
+ fields: [
2712
+ {
2713
+ name: "name",
2714
+ type: "text",
2715
+ index: true,
2716
+ unique: true
2717
+ },
2718
+ {
2719
+ name: "value",
2720
+ type: "longText"
2721
+ },
2722
+ {
2723
+ name: "encrypted",
2724
+ type: "boolean",
2725
+ default: false
2726
+ }
2727
+ ]
2728
+ };
2604
2729
 
2605
2730
  // src/registry/uppy.ts
2606
2731
  var import_express = require("express");
@@ -2996,34 +3121,7 @@ var createUppyRoutes = async (app) => {
2996
3121
  // src/registry/routes.ts
2997
3122
  var import_utils2 = require("@apollo/utils.keyvaluecache");
2998
3123
  var import_body_parser = __toESM(require("body-parser"), 1);
2999
- var import_crypto_js2 = __toESM(require("crypto-js"), 1);
3000
-
3001
- // src/registry/utils/claude-messages.ts
3002
- var CLAUDE_MESSAGES = {
3003
- authentication_error: `
3004
- \x1B[41m -- Authentication error please check your IMP token and try again. --
3005
- \x1B[0m`,
3006
- missing_body: `
3007
- \x1B[41m -- Missing body Anthropic response. --
3008
- \x1B[0m`,
3009
- missing_nextauth_secret: `
3010
- \x1B[41m -- Missing NEXTAUTH_SECRET in environment variables on the server. --
3011
- \x1B[0m`,
3012
- not_enabled: `
3013
- \x1B[31m
3014
- \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557
3015
- \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2588\u2588\u2557\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
3016
- \u2588\u2588\u2588\u2588\u2588\u2557 \u255A\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
3017
- \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
3018
- \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2554\u255D \u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
3019
- \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D
3020
- Intelligence Management Platform
3021
- \x1B[0m
3022
- \x1B[41m -- Your account has not been enabled to use Claude Code, please contact your admin or enable Claude Code in the user settings. --
3023
- \x1B[0m`
3024
- };
3025
-
3026
- // src/registry/routes.ts
3124
+ var import_crypto_js3 = __toESM(require("crypto-js"), 1);
3027
3125
  var REQUEST_SIZE_LIMIT = "50mb";
3028
3126
  var global_queues = {
3029
3127
  logs_cleaner: "logs-cleaner"
@@ -3130,7 +3228,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
3130
3228
  } else {
3131
3229
  console.log("===========================", "[EXULU] no redis server configured, not setting up recurring jobs.", "===========================");
3132
3230
  }
3133
- const schema = createSDL([usersSchema, rolesSchema, agentsSchema, jobsSchema, workflowSchema, evalResultsSchema, agentSessionsSchema, agentMessagesSchema]);
3231
+ const schema = createSDL([usersSchema, rolesSchema, agentsSchema, jobsSchema, workflowSchema, evalResultsSchema, agentSessionsSchema, agentMessagesSchema, variablesSchema]);
3134
3232
  console.log("[EXULU] graphql server");
3135
3233
  const server = new import_server3.ApolloServer({
3136
3234
  cache: new import_utils2.InMemoryLRUCache(),
@@ -3965,6 +4063,7 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
3965
4063
  const result = agent.generateStream({
3966
4064
  messages: req.body.messages,
3967
4065
  tools: enabledTools,
4066
+ configs: agentInstance.tools,
3968
4067
  statistics: {
3969
4068
  label: agent.name,
3970
4069
  trigger: "agent"
@@ -3975,7 +4074,8 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
3975
4074
  } else {
3976
4075
  const response = await agent.generateSync({
3977
4076
  messages: req.body.messages,
3978
- tools: enabledTools.map(),
4077
+ tools: enabledTools.map((tool2) => tool2.tool),
4078
+ configs: agentInstance.tools,
3979
4079
  statistics: {
3980
4080
  label: agent.name,
3981
4081
  trigger: "agent"
@@ -4092,8 +4192,25 @@ var createExpressRoutes = async (app, agents, tools, workflows, contexts) => {
4092
4192
  res.end(Buffer.from(arrayBuffer));
4093
4193
  return;
4094
4194
  }
4095
- const bytes = import_crypto_js2.default.AES.decrypt(authenticationResult.user?.anthropic_token, process.env.NEXTAUTH_SECRET);
4096
- const anthropicApiKey = bytes.toString(import_crypto_js2.default.enc.Utf8);
4195
+ const variableName = authenticationResult.user.anthropic_token;
4196
+ const variable = await db3.from("variables").where({ name: variableName }).first();
4197
+ if (!variable) {
4198
+ const arrayBuffer = createCustomAnthropicStreamingMessage(CLAUDE_MESSAGES.anthropic_token_variable_not_found);
4199
+ res.setHeader("Content-Type", "application/json");
4200
+ res.end(Buffer.from(arrayBuffer));
4201
+ return;
4202
+ }
4203
+ let anthropicApiKey = variable.value;
4204
+ if (!variable.encrypted) {
4205
+ const arrayBuffer = createCustomAnthropicStreamingMessage(CLAUDE_MESSAGES.anthropic_token_variable_not_encrypted);
4206
+ res.setHeader("Content-Type", "application/json");
4207
+ res.end(Buffer.from(arrayBuffer));
4208
+ return;
4209
+ }
4210
+ if (variable.encrypted) {
4211
+ const bytes = import_crypto_js3.default.AES.decrypt(variable.value, process.env.NEXTAUTH_SECRET);
4212
+ anthropicApiKey = bytes.toString(import_crypto_js3.default.enc.Utf8);
4213
+ }
4097
4214
  const headers = {
4098
4215
  "x-api-key": anthropicApiKey,
4099
4216
  "anthropic-version": "2023-06-01",
@@ -4605,129 +4722,6 @@ var defaultAgent = new ExuluAgent({
4605
4722
  }
4606
4723
  });
4607
4724
 
4608
- // src/templates/tools/browserbase.ts
4609
- var import_zod5 = require("zod");
4610
- var import_stagehand = require("@browserbasehq/stagehand");
4611
- var import_sdk = require("@browserbasehq/sdk");
4612
- var PROJECT_ID = "811444dd-6e6d-40b5-bd90-541c93e44be6";
4613
- process.env.BROWSERBASE_PROJECT_ID = PROJECT_ID;
4614
- var BB_API_KEY = "bb_live_LwMwNgZB5cIEKcBwMuAugrgNkFM";
4615
- async function createContext() {
4616
- const bb = new import_sdk.Browserbase({ apiKey: BB_API_KEY });
4617
- const context = await bb.contexts.create({
4618
- projectId: PROJECT_ID
4619
- });
4620
- return context;
4621
- }
4622
- async function createAuthSession(contextId) {
4623
- const bb = new import_sdk.Browserbase({ apiKey: BB_API_KEY });
4624
- const session = await bb.sessions.create({
4625
- projectId: PROJECT_ID,
4626
- browserSettings: {
4627
- context: {
4628
- id: contextId,
4629
- persist: true
4630
- }
4631
- }
4632
- /* proxies: [{ // not included in the free tier
4633
- type: "browserbase",
4634
- geolocation: {
4635
- city: CITY,
4636
- country: COUNTRY
4637
- }
4638
- }] */
4639
- });
4640
- const liveViewLinks = await bb.sessions.debug(session.id);
4641
- const liveViewLink = liveViewLinks.debuggerFullscreenUrl;
4642
- console.log(`\u{1F50D} Live View Link: ${liveViewLink}`);
4643
- console.log("Session URL: https://browserbase.com/sessions/" + session.id);
4644
- return {
4645
- url: liveViewLink,
4646
- id: session.id
4647
- };
4648
- }
4649
- var createSession = new ExuluTool({
4650
- id: `1234-5178-9423-4267`,
4651
- type: "function",
4652
- name: "Create a browserbase session.",
4653
- description: `
4654
- Creates a browserbase session and returns the live view url as well as
4655
- the session id as a JSON object. A browserbase session is a headless browser
4656
- that can be used to to visit websites and perform actions.
4657
- `,
4658
- execute: async () => {
4659
- const { id } = await createContext();
4660
- return await createAuthSession(id);
4661
- }
4662
- });
4663
- var askChatgpt = new ExuluTool({
4664
- id: `1234-5178-9423-4268`,
4665
- type: "function",
4666
- name: "ChatGPT browserbase operation.",
4667
- inputSchema: import_zod5.z.object({
4668
- session: import_zod5.z.string().describe("The session id of the browserbase session."),
4669
- question: import_zod5.z.string().describe("The question to ask ChatGPT.")
4670
- }),
4671
- description: `Uses an existing, authenticated browserbase session to visit ChatGPT and perform actions such as asking questions.`,
4672
- execute: async ({ session, question }) => {
4673
- const stagehand = new import_stagehand.Stagehand({
4674
- // With npx create-browser-app, this config is found
4675
- // in a separate stagehand.config.ts file
4676
- env: "BROWSERBASE",
4677
- // set to "LOCAL" for local development
4678
- apiKey: BB_API_KEY,
4679
- // todo make this a config variable the admin can set in the UI
4680
- modelName: "openai/gpt-4.1-mini",
4681
- // todo change to claude || optionally make configurable?
4682
- browserbaseSessionID: session,
4683
- modelClientOptions: {
4684
- apiKey: process.env.OPENAI_API_KEY
4685
- // todo make this a config variable the admin can set in the UI
4686
- }
4687
- });
4688
- await stagehand.init();
4689
- const page = stagehand.page;
4690
- await page.goto("https://chatgpt.com");
4691
- await page.act(`Type in '${question}' into the search bar`);
4692
- const { answer } = await page.extract({
4693
- instruction: "The answer to the question generated by ChatGPT.",
4694
- schema: import_zod5.z.object({
4695
- answer: import_zod5.z.string()
4696
- })
4697
- });
4698
- console.log(answer);
4699
- await stagehand.close();
4700
- return {
4701
- answer
4702
- };
4703
- }
4704
- });
4705
-
4706
- // src/templates/tools/jira.ts
4707
- var import_zod6 = require("zod");
4708
- var getTicket = new ExuluTool({
4709
- id: `1414-5179-1423-1269`,
4710
- name: "JIRA ticket retrieval.",
4711
- type: "function",
4712
- inputSchema: import_zod6.z.object({
4713
- ticketId: import_zod6.z.string().describe("The id of the ticket to retrieve.")
4714
- }),
4715
- description: `Retrieves a ticket from Jira.`,
4716
- execute: async ({ session, question }) => {
4717
- return {
4718
- name: "BYD-1234",
4719
- id: "12345678",
4720
- status: "Open",
4721
- description: "This is a test ticket",
4722
- assignee: "John Doe",
4723
- createdAt: "2021-01-01",
4724
- updatedAt: "2021-01-01",
4725
- dueDate: "2021-01-01",
4726
- priority: "High"
4727
- };
4728
- }
4729
- });
4730
-
4731
4725
  // src/registry/index.ts
4732
4726
  var ExuluApp = class {
4733
4727
  _agents = [];
@@ -4755,12 +4749,7 @@ var ExuluApp = class {
4755
4749
  // Add contexts as tools
4756
4750
  ...Object.values(contexts || {}).map((context) => context.tool()),
4757
4751
  // Add agents as tools
4758
- ...(agents || []).map((agent) => agent.tool()),
4759
- ...[
4760
- createSession,
4761
- askChatgpt,
4762
- getTicket
4763
- ]
4752
+ ...(agents || []).map((agent) => agent.tool())
4764
4753
  ];
4765
4754
  const contextsArray = Object.values(contexts || {});
4766
4755
  const queues2 = [
@@ -6096,6 +6085,7 @@ var generateApiKey = async (name, email) => {
6096
6085
 
6097
6086
  // src/postgres/init-db.ts
6098
6087
  var up = async function(knex) {
6088
+ console.log("[EXULU] Database up.");
6099
6089
  if (!await knex.schema.hasTable("agent_sessions")) {
6100
6090
  console.log("[EXULU] Creating agent_sessions table.");
6101
6091
  await knex.schema.createTable("agent_sessions", (table) => {
@@ -6103,11 +6093,11 @@ var up = async function(knex) {
6103
6093
  table.timestamp("createdAt").defaultTo(knex.fn.now());
6104
6094
  table.timestamp("updatedAt").defaultTo(knex.fn.now());
6105
6095
  for (const field of agentSessionsSchema.fields) {
6106
- const { type, name, default: defaultValue } = field;
6096
+ const { type, name, default: defaultValue, unique } = field;
6107
6097
  if (!type || !name) {
6108
6098
  continue;
6109
6099
  }
6110
- mapType(table, type, sanitizeName(name), defaultValue);
6100
+ mapType(table, type, sanitizeName(name), defaultValue, unique);
6111
6101
  }
6112
6102
  });
6113
6103
  }
@@ -6118,11 +6108,11 @@ var up = async function(knex) {
6118
6108
  table.timestamp("createdAt").defaultTo(knex.fn.now());
6119
6109
  table.timestamp("updatedAt").defaultTo(knex.fn.now());
6120
6110
  for (const field of agentMessagesSchema.fields) {
6121
- const { type, name, default: defaultValue } = field;
6111
+ const { type, name, default: defaultValue, unique } = field;
6122
6112
  if (!type || !name) {
6123
6113
  continue;
6124
6114
  }
6125
- mapType(table, type, sanitizeName(name), defaultValue);
6115
+ mapType(table, type, sanitizeName(name), defaultValue, unique);
6126
6116
  }
6127
6117
  });
6128
6118
  }
@@ -6133,11 +6123,11 @@ var up = async function(knex) {
6133
6123
  table.timestamp("createdAt").defaultTo(knex.fn.now());
6134
6124
  table.timestamp("updatedAt").defaultTo(knex.fn.now());
6135
6125
  for (const field of rolesSchema.fields) {
6136
- const { type, name, default: defaultValue } = field;
6126
+ const { type, name, default: defaultValue, unique } = field;
6137
6127
  if (!type || !name) {
6138
6128
  continue;
6139
6129
  }
6140
- mapType(table, type, sanitizeName(name), defaultValue);
6130
+ mapType(table, type, sanitizeName(name), defaultValue, unique);
6141
6131
  }
6142
6132
  });
6143
6133
  }
@@ -6148,11 +6138,11 @@ var up = async function(knex) {
6148
6138
  table.timestamp("createdAt").defaultTo(knex.fn.now());
6149
6139
  table.timestamp("updatedAt").defaultTo(knex.fn.now());
6150
6140
  for (const field of evalResultsSchema.fields) {
6151
- const { type, name, default: defaultValue } = field;
6141
+ const { type, name, default: defaultValue, unique } = field;
6152
6142
  if (!type || !name) {
6153
6143
  continue;
6154
6144
  }
6155
- mapType(table, type, sanitizeName(name), defaultValue);
6145
+ mapType(table, type, sanitizeName(name), defaultValue, unique);
6156
6146
  }
6157
6147
  });
6158
6148
  }
@@ -6163,11 +6153,11 @@ var up = async function(knex) {
6163
6153
  table.timestamp("createdAt").defaultTo(knex.fn.now());
6164
6154
  table.timestamp("updatedAt").defaultTo(knex.fn.now());
6165
6155
  for (const field of statisticsSchema.fields) {
6166
- const { type, name, default: defaultValue } = field;
6156
+ const { type, name, default: defaultValue, unique } = field;
6167
6157
  if (!type || !name) {
6168
6158
  continue;
6169
6159
  }
6170
- mapType(table, type, sanitizeName(name), defaultValue);
6160
+ mapType(table, type, sanitizeName(name), defaultValue, unique);
6171
6161
  }
6172
6162
  });
6173
6163
  }
@@ -6178,11 +6168,11 @@ var up = async function(knex) {
6178
6168
  table.timestamp("createdAt").defaultTo(knex.fn.now());
6179
6169
  table.timestamp("updatedAt").defaultTo(knex.fn.now());
6180
6170
  for (const field of jobsSchema.fields) {
6181
- const { type, name, default: defaultValue } = field;
6171
+ const { type, name, default: defaultValue, unique } = field;
6182
6172
  if (!type || !name) {
6183
6173
  continue;
6184
6174
  }
6185
- mapType(table, type, sanitizeName(name), defaultValue);
6175
+ mapType(table, type, sanitizeName(name), defaultValue, unique);
6186
6176
  }
6187
6177
  });
6188
6178
  }
@@ -6193,11 +6183,26 @@ var up = async function(knex) {
6193
6183
  table.timestamp("createdAt").defaultTo(knex.fn.now());
6194
6184
  table.timestamp("updatedAt").defaultTo(knex.fn.now());
6195
6185
  for (const field of agentsSchema.fields) {
6196
- const { type, name, default: defaultValue } = field;
6186
+ const { type, name, default: defaultValue, unique } = field;
6187
+ if (!type || !name) {
6188
+ continue;
6189
+ }
6190
+ mapType(table, type, sanitizeName(name), defaultValue, unique);
6191
+ }
6192
+ });
6193
+ }
6194
+ if (!await knex.schema.hasTable("variables")) {
6195
+ console.log("[EXULU] Creating variables table.");
6196
+ await knex.schema.createTable("variables", (table) => {
6197
+ table.uuid("id").primary().defaultTo(knex.fn.uuid());
6198
+ table.timestamp("createdAt").defaultTo(knex.fn.now());
6199
+ table.timestamp("updatedAt").defaultTo(knex.fn.now());
6200
+ for (const field of variablesSchema.fields) {
6201
+ const { type, name, default: defaultValue, unique } = field;
6197
6202
  if (!type || !name) {
6198
6203
  continue;
6199
6204
  }
6200
- mapType(table, type, sanitizeName(name), defaultValue);
6205
+ mapType(table, type, sanitizeName(name), defaultValue, unique);
6201
6206
  }
6202
6207
  });
6203
6208
  }
@@ -6223,14 +6228,14 @@ var up = async function(knex) {
6223
6228
  table.text("image");
6224
6229
  for (const field of usersSchema.fields) {
6225
6230
  console.log("[EXULU] field", field);
6226
- const { type, name, default: defaultValue } = field;
6231
+ const { type, name, default: defaultValue, unique } = field;
6227
6232
  if (name === "id" || name === "name" || name === "email" || name === "emailVerified" || name === "image") {
6228
6233
  continue;
6229
6234
  }
6230
6235
  if (!type || !name) {
6231
6236
  continue;
6232
6237
  }
6233
- mapType(table, type, sanitizeName(name), defaultValue);
6238
+ mapType(table, type, sanitizeName(name), defaultValue, unique);
6234
6239
  }
6235
6240
  });
6236
6241
  }