@exulu/backend 1.52.0 → 1.53.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
@@ -4044,6 +4044,7 @@ var ExuluContext2 = class {
4044
4044
  exuluConfig
4045
4045
  });
4046
4046
  if (!result) {
4047
+ console.log("[EXULU] Item filtered out by processor, skipping processing execution...");
4047
4048
  return {
4048
4049
  result: void 0,
4049
4050
  job: void 0
@@ -4244,10 +4245,12 @@ var ExuluContext2 = class {
4244
4245
  }
4245
4246
  }
4246
4247
  });
4248
+ console.log("[EXULU] Creating item", item);
4247
4249
  const mutation = db2.from(getTableName(this.id)).insert({
4248
4250
  ...item,
4249
4251
  tags: item.tags ? Array.isArray(item.tags) ? item.tags.join(",") : item.tags : void 0
4250
4252
  }).returning("id");
4253
+ console.log("[EXULU] Upsert", upsert);
4251
4254
  if (upsert) {
4252
4255
  if (item.external_id) {
4253
4256
  mutation.onConflict("external_id").merge();
@@ -4266,7 +4269,6 @@ var ExuluContext2 = class {
4266
4269
  let shouldGenerateEmbeddings = this.embedder && generateEmbeddingsOverwrite !== false && (generateEmbeddingsOverwrite || this.configuration.calculateVectors === "onInsert" || this.configuration.calculateVectors === "always");
4267
4270
  if (this.processor) {
4268
4271
  const processor = this.processor;
4269
- console.log("[EXULU] Processor found", processor);
4270
4272
  if (processor && (processor?.config?.trigger === "onInsert" || processor?.config?.trigger === "onUpdate" || processor?.config?.trigger === "always")) {
4271
4273
  const { job: processorJob, result: processorResult } = await this.processField(
4272
4274
  "api",
@@ -4281,7 +4283,7 @@ var ExuluContext2 = class {
4281
4283
  if (processorJob) {
4282
4284
  jobs.push(processorJob);
4283
4285
  }
4284
- if (!processorJob) {
4286
+ if (!processorJob && processorResult) {
4285
4287
  await db2.from(getTableName(this.id)).where({ id: results[0].id }).update({
4286
4288
  ...processorResult
4287
4289
  });
@@ -4352,7 +4354,7 @@ var ExuluContext2 = class {
4352
4354
  if (processorJob) {
4353
4355
  jobs.push(processorJob);
4354
4356
  }
4355
- if (!processorJob) {
4357
+ if (!processorJob && processorResult) {
4356
4358
  await db2.from(getTableName(this.id)).where({ id: record.id }).update({
4357
4359
  ...processorResult
4358
4360
  });
@@ -7420,7 +7422,32 @@ var createWorkers = async (providers, queues2, config, contexts, rerankers, eval
7420
7422
  );
7421
7423
  }
7422
7424
  const exuluStorage = new ExuluStorage({ config });
7423
- console.log("[EXULU] POS 2 -- EXULU CONTEXT PROCESS FIELD");
7425
+ if (context.processor.filter) {
7426
+ const result2 = await context.processor.filter({
7427
+ item: data.inputs,
7428
+ user: data.user,
7429
+ role: data.role,
7430
+ utils: {
7431
+ storage: exuluStorage
7432
+ },
7433
+ exuluConfig: config
7434
+ });
7435
+ if (!result2) {
7436
+ console.log("[EXULU] Item filtered out by processor, skipping processing execution...");
7437
+ return {
7438
+ result: "Item filtered out by processor, skipping processing execution...",
7439
+ // last message
7440
+ metadata: {
7441
+ item: {
7442
+ name: data.inputs?.name,
7443
+ id: data.inputs?.id,
7444
+ external_id: data.inputs?.external_id
7445
+ }
7446
+ }
7447
+ };
7448
+ }
7449
+ }
7450
+ console.log("[EXULU] POS 2 -- EXULU CONTEXT PROCESS FIELD", data.inputs);
7424
7451
  let processorResult = await context.processor.execute({
7425
7452
  item: data.inputs,
7426
7453
  user: data.user,
@@ -10863,7 +10890,6 @@ var providerRateLimiter = async (key, windowSeconds, limit, points) => {
10863
10890
 
10864
10891
  // src/exulu/routes.ts
10865
10892
  var import_zod_from_json_schema = require("zod-from-json-schema");
10866
- var import_zod8 = require("zod");
10867
10893
  var REQUEST_SIZE_LIMIT = "50mb";
10868
10894
  var getExuluVersionNumber = async () => {
10869
10895
  try {
@@ -11778,7 +11804,7 @@ var import_types2 = require("@modelcontextprotocol/sdk/types.js");
11778
11804
  var import_express4 = require("express");
11779
11805
  var import_api3 = require("@opentelemetry/api");
11780
11806
  var import_crypto_js7 = __toESM(require("crypto-js"), 1);
11781
- var import_zod9 = require("zod");
11807
+ var import_zod8 = require("zod");
11782
11808
  var SESSION_ID_HEADER = "mcp-session-id";
11783
11809
  var ExuluMCP = class {
11784
11810
  server = {};
@@ -11861,7 +11887,7 @@ var ExuluMCP = class {
11861
11887
  title: tool3.name + " agent",
11862
11888
  description: tool3.description,
11863
11889
  inputSchema: {
11864
- inputs: tool3.inputSchema || import_zod9.z.object({})
11890
+ inputs: tool3.inputSchema || import_zod8.z.object({})
11865
11891
  }
11866
11892
  },
11867
11893
  async ({ inputs }, args) => {
@@ -11913,7 +11939,7 @@ var ExuluMCP = class {
11913
11939
  title: "Get List of Prompt Templates",
11914
11940
  description: "Retrieves a list of prompt templates available for this agent. Returns the name, description, and ID of each template.",
11915
11941
  inputSchema: {
11916
- inputs: import_zod9.z.object({})
11942
+ inputs: import_zod8.z.object({})
11917
11943
  }
11918
11944
  },
11919
11945
  async ({ inputs }, args) => {
@@ -11959,8 +11985,8 @@ var ExuluMCP = class {
11959
11985
  title: "Get Prompt Template Details",
11960
11986
  description: "Retrieves the full details of a specific prompt template by ID, including the actual template content with variables.",
11961
11987
  inputSchema: {
11962
- inputs: import_zod9.z.object({
11963
- id: import_zod9.z.string().describe("The ID of the prompt template to retrieve")
11988
+ inputs: import_zod8.z.object({
11989
+ id: import_zod8.z.string().describe("The ID of the prompt template to retrieve")
11964
11990
  })
11965
11991
  }
11966
11992
  },
@@ -12868,7 +12894,7 @@ var ExuluEval = class {
12868
12894
  };
12869
12895
 
12870
12896
  // src/templates/evals/index.ts
12871
- var import_zod10 = require("zod");
12897
+ var import_zod9 = require("zod");
12872
12898
  var llmAsJudgeEval = () => {
12873
12899
  if (process.env.REDIS_HOST?.length && process.env.REDIS_PORT?.length) {
12874
12900
  return new ExuluEval({
@@ -12913,8 +12939,8 @@ var llmAsJudgeEval = () => {
12913
12939
  contexts: [],
12914
12940
  rerankers: [],
12915
12941
  prompt,
12916
- outputSchema: import_zod10.z.object({
12917
- score: import_zod10.z.number().min(0).max(100).describe("The score between 0 and 100.")
12942
+ outputSchema: import_zod9.z.object({
12943
+ score: import_zod9.z.number().min(0).max(100).describe("The score between 0 and 100.")
12918
12944
  }),
12919
12945
  providerapikey
12920
12946
  });
@@ -13142,12 +13168,12 @@ Usage:
13142
13168
  - If no todos exist yet, an empty list will be returned`;
13143
13169
 
13144
13170
  // src/templates/tools/todo/todo.ts
13145
- var import_zod11 = __toESM(require("zod"), 1);
13146
- var TodoSchema = import_zod11.default.object({
13147
- content: import_zod11.default.string().describe("Brief description of the task"),
13148
- status: import_zod11.default.string().describe("Current status of the task: pending, in_progress, completed, cancelled"),
13149
- priority: import_zod11.default.string().describe("Priority level of the task: high, medium, low"),
13150
- id: import_zod11.default.string().describe("Unique identifier for the todo item")
13171
+ var import_zod10 = __toESM(require("zod"), 1);
13172
+ var TodoSchema = import_zod10.default.object({
13173
+ content: import_zod10.default.string().describe("Brief description of the task"),
13174
+ status: import_zod10.default.string().describe("Current status of the task: pending, in_progress, completed, cancelled"),
13175
+ priority: import_zod10.default.string().describe("Priority level of the task: high, medium, low"),
13176
+ id: import_zod10.default.string().describe("Unique identifier for the todo item")
13151
13177
  });
13152
13178
  var TodoWriteTool = new ExuluTool({
13153
13179
  id: "todo_write",
@@ -13163,8 +13189,8 @@ var TodoWriteTool = new ExuluTool({
13163
13189
  default: todowrite_default
13164
13190
  }
13165
13191
  ],
13166
- inputSchema: import_zod11.default.object({
13167
- todos: import_zod11.default.array(TodoSchema).describe("The updated todo list")
13192
+ inputSchema: import_zod10.default.object({
13193
+ todos: import_zod10.default.array(TodoSchema).describe("The updated todo list")
13168
13194
  }),
13169
13195
  execute: async (inputs) => {
13170
13196
  const { sessionID, todos, user } = inputs;
@@ -13199,7 +13225,7 @@ var TodoReadTool = new ExuluTool({
13199
13225
  id: "todo_read",
13200
13226
  name: "Todo Read",
13201
13227
  description: "Use this tool to read your todo list",
13202
- inputSchema: import_zod11.default.object({}),
13228
+ inputSchema: import_zod10.default.object({}),
13203
13229
  type: "function",
13204
13230
  category: "todo",
13205
13231
  config: [
@@ -13237,6 +13263,222 @@ async function getTodos(sessionID) {
13237
13263
  }
13238
13264
  var todoTools = [TodoWriteTool, TodoReadTool];
13239
13265
 
13266
+ // src/templates/tools/question/questionask.txt
13267
+ var questionask_default = `Use this tool to ask the user a question with multiple choice answer options during your session. This helps you gather user input, clarify requirements, and make informed decisions based on user preferences.
13268
+
13269
+ ## When to Use This Tool
13270
+
13271
+ Use this tool when you need to:
13272
+
13273
+ 1. Get user input on implementation choices - When there are multiple valid approaches and you need the user to decide
13274
+ 2. Clarify ambiguous requirements - When the user's request could be interpreted in different ways
13275
+ 3. Gather preferences - When you need to know the user's preference for styling, naming, architecture, etc.
13276
+ 4. Validate assumptions - When you want to confirm your understanding before proceeding
13277
+ 5. Offer options - When presenting multiple solutions and letting the user choose
13278
+
13279
+ ## When NOT to Use This Tool
13280
+
13281
+ Skip using this tool when:
13282
+ 1. The answer is clear from context or previous messages
13283
+ 2. You're asking a yes/no question (use a simpler approach)
13284
+ 3. The question requires a free-form text answer (this tool is for multiple choice only)
13285
+ 4. You're asking for information that should be obvious from the codebase
13286
+
13287
+ ## How It Works
13288
+
13289
+ - Provide a question and an array of answer option strings
13290
+ - The tool automatically adds "None of the above..." as a final option
13291
+ - Each answer option is assigned a unique ID
13292
+ - The question is stored with a "pending" status until the user answers
13293
+ - Use the Question Read tool to check if the question has been answered
13294
+
13295
+ ## Examples
13296
+
13297
+ <example>
13298
+ User: Add authentication to my app
13299
+ Assistant: I need to ask the user which authentication method they prefer.
13300
+ *Uses Question Ask tool with:*
13301
+ question: "Which authentication method would you like to implement?"
13302
+ answerOptions: ["JWT tokens", "OAuth 2.0", "Session-based auth", "Firebase Auth"]
13303
+
13304
+ <reasoning>
13305
+ The assistant used the question tool because there are multiple valid authentication approaches and the user's preference will significantly impact the implementation.
13306
+ </reasoning>
13307
+ </example>
13308
+
13309
+ <example>
13310
+ User: Style this button
13311
+ Assistant: I need to know the user's styling preference.
13312
+ *Uses Question Ask tool with:*
13313
+ question: "What styling approach should I use for the button?"
13314
+ answerOptions: ["Tailwind CSS", "CSS Modules", "Styled Components", "Plain CSS"]
13315
+
13316
+ <reasoning>
13317
+ The assistant used the question tool because the codebase could support multiple styling approaches and the user's preference matters for consistency.
13318
+ </reasoning>
13319
+ </example>
13320
+
13321
+ <example>
13322
+ User: Add error handling
13323
+ Assistant: I'll implement comprehensive error handling with try-catch blocks and proper error messages.
13324
+ *Does not use the question tool*
13325
+
13326
+ <reasoning>
13327
+ The assistant did not use the question tool because error handling is a standard practice and there's a clear best approach that doesn't require user input.
13328
+ </reasoning>
13329
+ </example>
13330
+
13331
+ ## Answer Format
13332
+
13333
+ When you call this tool, answer options are automatically converted to this format:
13334
+ \`\`\`json
13335
+ [
13336
+ { "id": "randomId1", "text": "First option" },
13337
+ { "id": "randomId2", "text": "Second option" },
13338
+ { "id": "randomId3", "text": "Third option" },
13339
+ { "id": "randomId4", "text": "None of the above..." }
13340
+ ]
13341
+ \`\`\`
13342
+
13343
+ The "None of the above..." option is always added automatically, so you don't need to include it in your answerOptions array.
13344
+
13345
+ ## Reading Answers
13346
+
13347
+ After asking a question, use the Question Read tool to check if the user has answered. The question status will change from "pending" to "answered" and the selectedAnswerId field will contain the ID of the chosen answer.
13348
+ `;
13349
+
13350
+ // src/templates/tools/question/questionread.txt
13351
+ var questionread_default = 'Use this tool to read questions you\'ve asked and check if they\'ve been answered by the user. This tool helps you track the status of questions and retrieve the user\'s selected answers.\n\n## When to Use This Tool\n\nUse this tool proactively in these situations:\n- After asking a question to check if the user has responded\n- To retrieve the user\'s answer before proceeding with implementation\n- To review all questions and answers in the current session\n- When you need to reference a previous answer\n\n## How It Works\n\n- This tool takes no parameters (leave the input blank or empty)\n- Returns an array of all questions in the session\n- Each question includes:\n - `id`: Unique identifier for the question\n - `question`: The question text\n - `answerOptions`: Array of answer options with their IDs and text\n - `status`: Either "pending" (not answered) or "answered"\n - `selectedAnswerId`: The ID of the chosen answer (only present if answered)\n\n## Usage Pattern\n\nTypically you\'ll:\n1. Use Question Ask to pose a question\n2. Wait for the user to respond\n3. Use Question Read to check the answer\n4. Find the selected answer by matching the `selectedAnswerId` with an option in `answerOptions`\n5. Proceed with implementation based on the user\'s choice\n\n## Example Response\n\n```json\n[\n {\n "id": "question123",\n "question": "Which authentication method would you like to implement?",\n "answerOptions": [\n { "id": "ans1", "text": "JWT tokens" },\n { "id": "ans2", "text": "OAuth 2.0" },\n { "id": "ans3", "text": "Session-based auth" },\n { "id": "ans4", "text": "None of the above..." }\n ],\n "status": "answered",\n "selectedAnswerId": "ans1"\n }\n]\n```\n\nIn this example, the user selected "JWT tokens" (id: ans1).\n\n## Important Notes\n\n- If no questions exist in the session, an empty array will be returned\n- Questions remain in the session even after being answered for reference\n- Use the `selectedAnswerId` to find which answer option the user chose by matching it against the `id` field in `answerOptions`\n';
13352
+
13353
+ // src/templates/tools/question/question.ts
13354
+ var import_zod11 = __toESM(require("zod"), 1);
13355
+ var import_node_crypto6 = require("crypto");
13356
+ var AnswerOptionSchema = import_zod11.default.object({
13357
+ id: import_zod11.default.string().describe("Unique identifier for the answer option"),
13358
+ text: import_zod11.default.string().describe("The text of the answer option")
13359
+ });
13360
+ var _QuestionSchema = import_zod11.default.object({
13361
+ id: import_zod11.default.string().describe("Unique identifier for the question"),
13362
+ question: import_zod11.default.string().describe("The question to ask the user"),
13363
+ answerOptions: import_zod11.default.array(AnswerOptionSchema).describe("Array of possible answer options"),
13364
+ selectedAnswerId: import_zod11.default.string().optional().describe("The ID of the answer option selected by the user"),
13365
+ status: import_zod11.default.enum(["pending", "answered"]).describe("Status of the question: pending or answered")
13366
+ });
13367
+ var QuestionAskTool = new ExuluTool({
13368
+ id: "question_ask",
13369
+ name: "Question Ask",
13370
+ description: "Use this tool to ask a question to the user with multiple choice answers",
13371
+ type: "function",
13372
+ category: "question",
13373
+ config: [
13374
+ {
13375
+ name: "description",
13376
+ description: "The description of the question tool, if set overwrites the default description.",
13377
+ type: "string",
13378
+ default: questionask_default
13379
+ }
13380
+ ],
13381
+ inputSchema: import_zod11.default.object({
13382
+ question: import_zod11.default.string().describe("The question to ask the user"),
13383
+ answerOptions: import_zod11.default.array(import_zod11.default.string()).describe("Array of possible answer options (strings)")
13384
+ }),
13385
+ execute: async (inputs) => {
13386
+ const { sessionID, question, answerOptions, user } = inputs;
13387
+ if (!user) {
13388
+ throw new Error(
13389
+ "No authenticated user available, a user is required for the question ask tool, this likely means the tool was called outside a session like in an MCP or API call instead of as part of an authenticated session."
13390
+ );
13391
+ }
13392
+ if (!sessionID) {
13393
+ throw new Error(
13394
+ "Session ID is required for the question ask tool, this likely means the tool was called outside a session like in an MCP or API call instead of as part of a conversation."
13395
+ );
13396
+ }
13397
+ const session = await getSession({ sessionID });
13398
+ if (!session?.id) {
13399
+ throw new Error(
13400
+ "Session with ID " + sessionID + " not found in the question ask tool."
13401
+ );
13402
+ }
13403
+ const hasAccessToSession = await checkRecordAccess(session, "read", user);
13404
+ if (!hasAccessToSession) {
13405
+ throw new Error("You don't have access to this session " + session.id + ".");
13406
+ }
13407
+ const answerOptionsWithIds = answerOptions.map((text) => ({
13408
+ id: (0, import_node_crypto6.randomUUID)(),
13409
+ text
13410
+ }));
13411
+ answerOptionsWithIds.push({
13412
+ id: (0, import_node_crypto6.randomUUID)(),
13413
+ text: "None of the above..."
13414
+ });
13415
+ const newQuestion = {
13416
+ id: (0, import_node_crypto6.randomUUID)(),
13417
+ question,
13418
+ answerOptions: answerOptionsWithIds,
13419
+ status: "pending"
13420
+ };
13421
+ await addQuestion({
13422
+ session,
13423
+ question: newQuestion
13424
+ });
13425
+ return {
13426
+ result: JSON.stringify(
13427
+ {
13428
+ questionId: newQuestion.id,
13429
+ question: newQuestion.question,
13430
+ answerOptions: newQuestion.answerOptions,
13431
+ status: newQuestion.status
13432
+ },
13433
+ null,
13434
+ 2
13435
+ )
13436
+ };
13437
+ }
13438
+ });
13439
+ var QuestionReadTool = new ExuluTool({
13440
+ id: "question_read",
13441
+ name: "Question Read",
13442
+ description: "Use this tool to read questions and their answers",
13443
+ inputSchema: import_zod11.default.object({}),
13444
+ type: "function",
13445
+ category: "question",
13446
+ config: [
13447
+ {
13448
+ name: "description",
13449
+ description: "The description of the question read tool, if set overwrites the default description.",
13450
+ type: "string",
13451
+ default: questionread_default
13452
+ }
13453
+ ],
13454
+ execute: async (inputs) => {
13455
+ const { sessionID } = inputs;
13456
+ const questions = await getQuestions(sessionID);
13457
+ return {
13458
+ result: JSON.stringify(questions, null, 2)
13459
+ };
13460
+ }
13461
+ });
13462
+ async function addQuestion(input) {
13463
+ const metadata = input.session.metadata ?? {};
13464
+ metadata["questions"] ??= [];
13465
+ metadata["questions"].push(input.question);
13466
+ const { db: db2 } = await postgresClient();
13467
+ await db2.from("agent_sessions").where({ id: input.session.id }).update({
13468
+ metadata
13469
+ });
13470
+ return input.session;
13471
+ }
13472
+ async function getQuestions(sessionID) {
13473
+ const { db: db2 } = await postgresClient();
13474
+ const session = await db2.from("agent_sessions").where({ id: sessionID }).first();
13475
+ if (!session) {
13476
+ throw new Error("Session not found for session ID: " + sessionID);
13477
+ }
13478
+ return session.metadata?.questions ?? [];
13479
+ }
13480
+ var questionTools = [QuestionAskTool, QuestionReadTool];
13481
+
13240
13482
  // src/templates/tools/perplexity.ts
13241
13483
  var import_zod12 = __toESM(require("zod"), 1);
13242
13484
  var import_perplexity_ai = __toESM(require("@perplexity-ai/perplexity_ai"), 1);
@@ -13347,14 +13589,29 @@ var isValidPostgresName = (id) => {
13347
13589
 
13348
13590
  // src/exulu/app/index.ts
13349
13591
  var isDev = process.env.NODE_ENV !== "production";
13592
+ var lineLimitFormat = import_winston2.default.format((info) => {
13593
+ if (typeof info.message === "string") {
13594
+ const lines = info.message.split("\n");
13595
+ if (lines.length > 50) {
13596
+ const truncatedLines = lines.slice(0, 50);
13597
+ truncatedLines.push(`... (${lines.length - 50} more lines omitted)`);
13598
+ info.message = truncatedLines.join("\n");
13599
+ }
13600
+ }
13601
+ return info;
13602
+ });
13350
13603
  var consoleTransport = new import_winston2.default.transports.Console({
13351
13604
  format: isDev ? import_winston2.default.format.combine(
13605
+ lineLimitFormat(),
13352
13606
  import_winston2.default.format.colorize(),
13353
13607
  import_winston2.default.format.timestamp({ format: "HH:mm:ss" }),
13354
13608
  import_winston2.default.format.printf(({ timestamp, level, message }) => {
13355
13609
  return `${timestamp} [${level}] ${message}`;
13356
13610
  })
13357
- ) : import_winston2.default.format.json()
13611
+ ) : import_winston2.default.format.combine(
13612
+ lineLimitFormat(),
13613
+ import_winston2.default.format.json()
13614
+ )
13358
13615
  });
13359
13616
  var formatArg = (arg) => typeof arg === "object" ? import_util.default.inspect(arg, { depth: null, colors: isDev }) : String(arg);
13360
13617
  var createLogMethod = (logger, logLevel) => {
@@ -13424,6 +13681,7 @@ var ExuluApp2 = class {
13424
13681
  this._tools = [
13425
13682
  ...tools ?? [],
13426
13683
  ...todoTools,
13684
+ ...questionTools,
13427
13685
  ...perplexityTools,
13428
13686
  // Add contexts as tools
13429
13687
  ...Object.values(contexts || {}).map((context) => context.tool()).filter(Boolean)
package/dist/index.d.cts CHANGED
@@ -241,7 +241,7 @@ declare class ExuluStorage {
241
241
  type ExuluContextProcessor = {
242
242
  name: string;
243
243
  description: string;
244
- filter: ({ item, user, role, utils, exuluConfig, }: {
244
+ filter?: ({ item, user, role, utils, exuluConfig, }: {
245
245
  item: Item;
246
246
  user?: number;
247
247
  role?: string;
package/dist/index.d.ts CHANGED
@@ -241,7 +241,7 @@ declare class ExuluStorage {
241
241
  type ExuluContextProcessor = {
242
242
  name: string;
243
243
  description: string;
244
- filter: ({ item, user, role, utils, exuluConfig, }: {
244
+ filter?: ({ item, user, role, utils, exuluConfig, }: {
245
245
  item: Item;
246
246
  user?: number;
247
247
  role?: string;
package/dist/index.js CHANGED
@@ -4003,6 +4003,7 @@ var ExuluContext2 = class {
4003
4003
  exuluConfig
4004
4004
  });
4005
4005
  if (!result) {
4006
+ console.log("[EXULU] Item filtered out by processor, skipping processing execution...");
4006
4007
  return {
4007
4008
  result: void 0,
4008
4009
  job: void 0
@@ -4203,10 +4204,12 @@ var ExuluContext2 = class {
4203
4204
  }
4204
4205
  }
4205
4206
  });
4207
+ console.log("[EXULU] Creating item", item);
4206
4208
  const mutation = db2.from(getTableName(this.id)).insert({
4207
4209
  ...item,
4208
4210
  tags: item.tags ? Array.isArray(item.tags) ? item.tags.join(",") : item.tags : void 0
4209
4211
  }).returning("id");
4212
+ console.log("[EXULU] Upsert", upsert);
4210
4213
  if (upsert) {
4211
4214
  if (item.external_id) {
4212
4215
  mutation.onConflict("external_id").merge();
@@ -4225,7 +4228,6 @@ var ExuluContext2 = class {
4225
4228
  let shouldGenerateEmbeddings = this.embedder && generateEmbeddingsOverwrite !== false && (generateEmbeddingsOverwrite || this.configuration.calculateVectors === "onInsert" || this.configuration.calculateVectors === "always");
4226
4229
  if (this.processor) {
4227
4230
  const processor = this.processor;
4228
- console.log("[EXULU] Processor found", processor);
4229
4231
  if (processor && (processor?.config?.trigger === "onInsert" || processor?.config?.trigger === "onUpdate" || processor?.config?.trigger === "always")) {
4230
4232
  const { job: processorJob, result: processorResult } = await this.processField(
4231
4233
  "api",
@@ -4240,7 +4242,7 @@ var ExuluContext2 = class {
4240
4242
  if (processorJob) {
4241
4243
  jobs.push(processorJob);
4242
4244
  }
4243
- if (!processorJob) {
4245
+ if (!processorJob && processorResult) {
4244
4246
  await db2.from(getTableName(this.id)).where({ id: results[0].id }).update({
4245
4247
  ...processorResult
4246
4248
  });
@@ -4311,7 +4313,7 @@ var ExuluContext2 = class {
4311
4313
  if (processorJob) {
4312
4314
  jobs.push(processorJob);
4313
4315
  }
4314
- if (!processorJob) {
4316
+ if (!processorJob && processorResult) {
4315
4317
  await db2.from(getTableName(this.id)).where({ id: record.id }).update({
4316
4318
  ...processorResult
4317
4319
  });
@@ -7379,7 +7381,32 @@ var createWorkers = async (providers, queues2, config, contexts, rerankers, eval
7379
7381
  );
7380
7382
  }
7381
7383
  const exuluStorage = new ExuluStorage({ config });
7382
- console.log("[EXULU] POS 2 -- EXULU CONTEXT PROCESS FIELD");
7384
+ if (context.processor.filter) {
7385
+ const result2 = await context.processor.filter({
7386
+ item: data.inputs,
7387
+ user: data.user,
7388
+ role: data.role,
7389
+ utils: {
7390
+ storage: exuluStorage
7391
+ },
7392
+ exuluConfig: config
7393
+ });
7394
+ if (!result2) {
7395
+ console.log("[EXULU] Item filtered out by processor, skipping processing execution...");
7396
+ return {
7397
+ result: "Item filtered out by processor, skipping processing execution...",
7398
+ // last message
7399
+ metadata: {
7400
+ item: {
7401
+ name: data.inputs?.name,
7402
+ id: data.inputs?.id,
7403
+ external_id: data.inputs?.external_id
7404
+ }
7405
+ }
7406
+ };
7407
+ }
7408
+ }
7409
+ console.log("[EXULU] POS 2 -- EXULU CONTEXT PROCESS FIELD", data.inputs);
7383
7410
  let processorResult = await context.processor.execute({
7384
7411
  item: data.inputs,
7385
7412
  user: data.user,
@@ -10829,7 +10856,6 @@ var providerRateLimiter = async (key, windowSeconds, limit, points) => {
10829
10856
 
10830
10857
  // src/exulu/routes.ts
10831
10858
  import { convertJsonSchemaToZod } from "zod-from-json-schema";
10832
- import "zod";
10833
10859
  var REQUEST_SIZE_LIMIT = "50mb";
10834
10860
  var getExuluVersionNumber = async () => {
10835
10861
  try {
@@ -11744,7 +11770,7 @@ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
11744
11770
  import "express";
11745
11771
  import "@opentelemetry/api";
11746
11772
  import CryptoJS7 from "crypto-js";
11747
- import { z as z9 } from "zod";
11773
+ import { z as z8 } from "zod";
11748
11774
  var SESSION_ID_HEADER = "mcp-session-id";
11749
11775
  var ExuluMCP = class {
11750
11776
  server = {};
@@ -11827,7 +11853,7 @@ var ExuluMCP = class {
11827
11853
  title: tool3.name + " agent",
11828
11854
  description: tool3.description,
11829
11855
  inputSchema: {
11830
- inputs: tool3.inputSchema || z9.object({})
11856
+ inputs: tool3.inputSchema || z8.object({})
11831
11857
  }
11832
11858
  },
11833
11859
  async ({ inputs }, args) => {
@@ -11879,7 +11905,7 @@ var ExuluMCP = class {
11879
11905
  title: "Get List of Prompt Templates",
11880
11906
  description: "Retrieves a list of prompt templates available for this agent. Returns the name, description, and ID of each template.",
11881
11907
  inputSchema: {
11882
- inputs: z9.object({})
11908
+ inputs: z8.object({})
11883
11909
  }
11884
11910
  },
11885
11911
  async ({ inputs }, args) => {
@@ -11925,8 +11951,8 @@ var ExuluMCP = class {
11925
11951
  title: "Get Prompt Template Details",
11926
11952
  description: "Retrieves the full details of a specific prompt template by ID, including the actual template content with variables.",
11927
11953
  inputSchema: {
11928
- inputs: z9.object({
11929
- id: z9.string().describe("The ID of the prompt template to retrieve")
11954
+ inputs: z8.object({
11955
+ id: z8.string().describe("The ID of the prompt template to retrieve")
11930
11956
  })
11931
11957
  }
11932
11958
  },
@@ -12834,7 +12860,7 @@ var ExuluEval = class {
12834
12860
  };
12835
12861
 
12836
12862
  // src/templates/evals/index.ts
12837
- import { z as z10 } from "zod";
12863
+ import { z as z9 } from "zod";
12838
12864
  var llmAsJudgeEval = () => {
12839
12865
  if (process.env.REDIS_HOST?.length && process.env.REDIS_PORT?.length) {
12840
12866
  return new ExuluEval({
@@ -12879,8 +12905,8 @@ var llmAsJudgeEval = () => {
12879
12905
  contexts: [],
12880
12906
  rerankers: [],
12881
12907
  prompt,
12882
- outputSchema: z10.object({
12883
- score: z10.number().min(0).max(100).describe("The score between 0 and 100.")
12908
+ outputSchema: z9.object({
12909
+ score: z9.number().min(0).max(100).describe("The score between 0 and 100.")
12884
12910
  }),
12885
12911
  providerapikey
12886
12912
  });
@@ -13108,12 +13134,12 @@ Usage:
13108
13134
  - If no todos exist yet, an empty list will be returned`;
13109
13135
 
13110
13136
  // src/templates/tools/todo/todo.ts
13111
- import z11 from "zod";
13112
- var TodoSchema = z11.object({
13113
- content: z11.string().describe("Brief description of the task"),
13114
- status: z11.string().describe("Current status of the task: pending, in_progress, completed, cancelled"),
13115
- priority: z11.string().describe("Priority level of the task: high, medium, low"),
13116
- id: z11.string().describe("Unique identifier for the todo item")
13137
+ import z10 from "zod";
13138
+ var TodoSchema = z10.object({
13139
+ content: z10.string().describe("Brief description of the task"),
13140
+ status: z10.string().describe("Current status of the task: pending, in_progress, completed, cancelled"),
13141
+ priority: z10.string().describe("Priority level of the task: high, medium, low"),
13142
+ id: z10.string().describe("Unique identifier for the todo item")
13117
13143
  });
13118
13144
  var TodoWriteTool = new ExuluTool({
13119
13145
  id: "todo_write",
@@ -13129,8 +13155,8 @@ var TodoWriteTool = new ExuluTool({
13129
13155
  default: todowrite_default
13130
13156
  }
13131
13157
  ],
13132
- inputSchema: z11.object({
13133
- todos: z11.array(TodoSchema).describe("The updated todo list")
13158
+ inputSchema: z10.object({
13159
+ todos: z10.array(TodoSchema).describe("The updated todo list")
13134
13160
  }),
13135
13161
  execute: async (inputs) => {
13136
13162
  const { sessionID, todos, user } = inputs;
@@ -13165,7 +13191,7 @@ var TodoReadTool = new ExuluTool({
13165
13191
  id: "todo_read",
13166
13192
  name: "Todo Read",
13167
13193
  description: "Use this tool to read your todo list",
13168
- inputSchema: z11.object({}),
13194
+ inputSchema: z10.object({}),
13169
13195
  type: "function",
13170
13196
  category: "todo",
13171
13197
  config: [
@@ -13203,6 +13229,222 @@ async function getTodos(sessionID) {
13203
13229
  }
13204
13230
  var todoTools = [TodoWriteTool, TodoReadTool];
13205
13231
 
13232
+ // src/templates/tools/question/questionask.txt
13233
+ var questionask_default = `Use this tool to ask the user a question with multiple choice answer options during your session. This helps you gather user input, clarify requirements, and make informed decisions based on user preferences.
13234
+
13235
+ ## When to Use This Tool
13236
+
13237
+ Use this tool when you need to:
13238
+
13239
+ 1. Get user input on implementation choices - When there are multiple valid approaches and you need the user to decide
13240
+ 2. Clarify ambiguous requirements - When the user's request could be interpreted in different ways
13241
+ 3. Gather preferences - When you need to know the user's preference for styling, naming, architecture, etc.
13242
+ 4. Validate assumptions - When you want to confirm your understanding before proceeding
13243
+ 5. Offer options - When presenting multiple solutions and letting the user choose
13244
+
13245
+ ## When NOT to Use This Tool
13246
+
13247
+ Skip using this tool when:
13248
+ 1. The answer is clear from context or previous messages
13249
+ 2. You're asking a yes/no question (use a simpler approach)
13250
+ 3. The question requires a free-form text answer (this tool is for multiple choice only)
13251
+ 4. You're asking for information that should be obvious from the codebase
13252
+
13253
+ ## How It Works
13254
+
13255
+ - Provide a question and an array of answer option strings
13256
+ - The tool automatically adds "None of the above..." as a final option
13257
+ - Each answer option is assigned a unique ID
13258
+ - The question is stored with a "pending" status until the user answers
13259
+ - Use the Question Read tool to check if the question has been answered
13260
+
13261
+ ## Examples
13262
+
13263
+ <example>
13264
+ User: Add authentication to my app
13265
+ Assistant: I need to ask the user which authentication method they prefer.
13266
+ *Uses Question Ask tool with:*
13267
+ question: "Which authentication method would you like to implement?"
13268
+ answerOptions: ["JWT tokens", "OAuth 2.0", "Session-based auth", "Firebase Auth"]
13269
+
13270
+ <reasoning>
13271
+ The assistant used the question tool because there are multiple valid authentication approaches and the user's preference will significantly impact the implementation.
13272
+ </reasoning>
13273
+ </example>
13274
+
13275
+ <example>
13276
+ User: Style this button
13277
+ Assistant: I need to know the user's styling preference.
13278
+ *Uses Question Ask tool with:*
13279
+ question: "What styling approach should I use for the button?"
13280
+ answerOptions: ["Tailwind CSS", "CSS Modules", "Styled Components", "Plain CSS"]
13281
+
13282
+ <reasoning>
13283
+ The assistant used the question tool because the codebase could support multiple styling approaches and the user's preference matters for consistency.
13284
+ </reasoning>
13285
+ </example>
13286
+
13287
+ <example>
13288
+ User: Add error handling
13289
+ Assistant: I'll implement comprehensive error handling with try-catch blocks and proper error messages.
13290
+ *Does not use the question tool*
13291
+
13292
+ <reasoning>
13293
+ The assistant did not use the question tool because error handling is a standard practice and there's a clear best approach that doesn't require user input.
13294
+ </reasoning>
13295
+ </example>
13296
+
13297
+ ## Answer Format
13298
+
13299
+ When you call this tool, answer options are automatically converted to this format:
13300
+ \`\`\`json
13301
+ [
13302
+ { "id": "randomId1", "text": "First option" },
13303
+ { "id": "randomId2", "text": "Second option" },
13304
+ { "id": "randomId3", "text": "Third option" },
13305
+ { "id": "randomId4", "text": "None of the above..." }
13306
+ ]
13307
+ \`\`\`
13308
+
13309
+ The "None of the above..." option is always added automatically, so you don't need to include it in your answerOptions array.
13310
+
13311
+ ## Reading Answers
13312
+
13313
+ After asking a question, use the Question Read tool to check if the user has answered. The question status will change from "pending" to "answered" and the selectedAnswerId field will contain the ID of the chosen answer.
13314
+ `;
13315
+
13316
+ // src/templates/tools/question/questionread.txt
13317
+ var questionread_default = 'Use this tool to read questions you\'ve asked and check if they\'ve been answered by the user. This tool helps you track the status of questions and retrieve the user\'s selected answers.\n\n## When to Use This Tool\n\nUse this tool proactively in these situations:\n- After asking a question to check if the user has responded\n- To retrieve the user\'s answer before proceeding with implementation\n- To review all questions and answers in the current session\n- When you need to reference a previous answer\n\n## How It Works\n\n- This tool takes no parameters (leave the input blank or empty)\n- Returns an array of all questions in the session\n- Each question includes:\n - `id`: Unique identifier for the question\n - `question`: The question text\n - `answerOptions`: Array of answer options with their IDs and text\n - `status`: Either "pending" (not answered) or "answered"\n - `selectedAnswerId`: The ID of the chosen answer (only present if answered)\n\n## Usage Pattern\n\nTypically you\'ll:\n1. Use Question Ask to pose a question\n2. Wait for the user to respond\n3. Use Question Read to check the answer\n4. Find the selected answer by matching the `selectedAnswerId` with an option in `answerOptions`\n5. Proceed with implementation based on the user\'s choice\n\n## Example Response\n\n```json\n[\n {\n "id": "question123",\n "question": "Which authentication method would you like to implement?",\n "answerOptions": [\n { "id": "ans1", "text": "JWT tokens" },\n { "id": "ans2", "text": "OAuth 2.0" },\n { "id": "ans3", "text": "Session-based auth" },\n { "id": "ans4", "text": "None of the above..." }\n ],\n "status": "answered",\n "selectedAnswerId": "ans1"\n }\n]\n```\n\nIn this example, the user selected "JWT tokens" (id: ans1).\n\n## Important Notes\n\n- If no questions exist in the session, an empty array will be returned\n- Questions remain in the session even after being answered for reference\n- Use the `selectedAnswerId` to find which answer option the user chose by matching it against the `id` field in `answerOptions`\n';
13318
+
13319
+ // src/templates/tools/question/question.ts
13320
+ import z11 from "zod";
13321
+ import { randomUUID as randomUUID6 } from "crypto";
13322
+ var AnswerOptionSchema = z11.object({
13323
+ id: z11.string().describe("Unique identifier for the answer option"),
13324
+ text: z11.string().describe("The text of the answer option")
13325
+ });
13326
+ var _QuestionSchema = z11.object({
13327
+ id: z11.string().describe("Unique identifier for the question"),
13328
+ question: z11.string().describe("The question to ask the user"),
13329
+ answerOptions: z11.array(AnswerOptionSchema).describe("Array of possible answer options"),
13330
+ selectedAnswerId: z11.string().optional().describe("The ID of the answer option selected by the user"),
13331
+ status: z11.enum(["pending", "answered"]).describe("Status of the question: pending or answered")
13332
+ });
13333
+ var QuestionAskTool = new ExuluTool({
13334
+ id: "question_ask",
13335
+ name: "Question Ask",
13336
+ description: "Use this tool to ask a question to the user with multiple choice answers",
13337
+ type: "function",
13338
+ category: "question",
13339
+ config: [
13340
+ {
13341
+ name: "description",
13342
+ description: "The description of the question tool, if set overwrites the default description.",
13343
+ type: "string",
13344
+ default: questionask_default
13345
+ }
13346
+ ],
13347
+ inputSchema: z11.object({
13348
+ question: z11.string().describe("The question to ask the user"),
13349
+ answerOptions: z11.array(z11.string()).describe("Array of possible answer options (strings)")
13350
+ }),
13351
+ execute: async (inputs) => {
13352
+ const { sessionID, question, answerOptions, user } = inputs;
13353
+ if (!user) {
13354
+ throw new Error(
13355
+ "No authenticated user available, a user is required for the question ask tool, this likely means the tool was called outside a session like in an MCP or API call instead of as part of an authenticated session."
13356
+ );
13357
+ }
13358
+ if (!sessionID) {
13359
+ throw new Error(
13360
+ "Session ID is required for the question ask tool, this likely means the tool was called outside a session like in an MCP or API call instead of as part of a conversation."
13361
+ );
13362
+ }
13363
+ const session = await getSession({ sessionID });
13364
+ if (!session?.id) {
13365
+ throw new Error(
13366
+ "Session with ID " + sessionID + " not found in the question ask tool."
13367
+ );
13368
+ }
13369
+ const hasAccessToSession = await checkRecordAccess(session, "read", user);
13370
+ if (!hasAccessToSession) {
13371
+ throw new Error("You don't have access to this session " + session.id + ".");
13372
+ }
13373
+ const answerOptionsWithIds = answerOptions.map((text) => ({
13374
+ id: randomUUID6(),
13375
+ text
13376
+ }));
13377
+ answerOptionsWithIds.push({
13378
+ id: randomUUID6(),
13379
+ text: "None of the above..."
13380
+ });
13381
+ const newQuestion = {
13382
+ id: randomUUID6(),
13383
+ question,
13384
+ answerOptions: answerOptionsWithIds,
13385
+ status: "pending"
13386
+ };
13387
+ await addQuestion({
13388
+ session,
13389
+ question: newQuestion
13390
+ });
13391
+ return {
13392
+ result: JSON.stringify(
13393
+ {
13394
+ questionId: newQuestion.id,
13395
+ question: newQuestion.question,
13396
+ answerOptions: newQuestion.answerOptions,
13397
+ status: newQuestion.status
13398
+ },
13399
+ null,
13400
+ 2
13401
+ )
13402
+ };
13403
+ }
13404
+ });
13405
+ var QuestionReadTool = new ExuluTool({
13406
+ id: "question_read",
13407
+ name: "Question Read",
13408
+ description: "Use this tool to read questions and their answers",
13409
+ inputSchema: z11.object({}),
13410
+ type: "function",
13411
+ category: "question",
13412
+ config: [
13413
+ {
13414
+ name: "description",
13415
+ description: "The description of the question read tool, if set overwrites the default description.",
13416
+ type: "string",
13417
+ default: questionread_default
13418
+ }
13419
+ ],
13420
+ execute: async (inputs) => {
13421
+ const { sessionID } = inputs;
13422
+ const questions = await getQuestions(sessionID);
13423
+ return {
13424
+ result: JSON.stringify(questions, null, 2)
13425
+ };
13426
+ }
13427
+ });
13428
+ async function addQuestion(input) {
13429
+ const metadata = input.session.metadata ?? {};
13430
+ metadata["questions"] ??= [];
13431
+ metadata["questions"].push(input.question);
13432
+ const { db: db2 } = await postgresClient();
13433
+ await db2.from("agent_sessions").where({ id: input.session.id }).update({
13434
+ metadata
13435
+ });
13436
+ return input.session;
13437
+ }
13438
+ async function getQuestions(sessionID) {
13439
+ const { db: db2 } = await postgresClient();
13440
+ const session = await db2.from("agent_sessions").where({ id: sessionID }).first();
13441
+ if (!session) {
13442
+ throw new Error("Session not found for session ID: " + sessionID);
13443
+ }
13444
+ return session.metadata?.questions ?? [];
13445
+ }
13446
+ var questionTools = [QuestionAskTool, QuestionReadTool];
13447
+
13206
13448
  // src/templates/tools/perplexity.ts
13207
13449
  import z12 from "zod";
13208
13450
  import Perplexity from "@perplexity-ai/perplexity_ai";
@@ -13313,14 +13555,29 @@ var isValidPostgresName = (id) => {
13313
13555
 
13314
13556
  // src/exulu/app/index.ts
13315
13557
  var isDev = process.env.NODE_ENV !== "production";
13558
+ var lineLimitFormat = winston2.format((info) => {
13559
+ if (typeof info.message === "string") {
13560
+ const lines = info.message.split("\n");
13561
+ if (lines.length > 50) {
13562
+ const truncatedLines = lines.slice(0, 50);
13563
+ truncatedLines.push(`... (${lines.length - 50} more lines omitted)`);
13564
+ info.message = truncatedLines.join("\n");
13565
+ }
13566
+ }
13567
+ return info;
13568
+ });
13316
13569
  var consoleTransport = new winston2.transports.Console({
13317
13570
  format: isDev ? winston2.format.combine(
13571
+ lineLimitFormat(),
13318
13572
  winston2.format.colorize(),
13319
13573
  winston2.format.timestamp({ format: "HH:mm:ss" }),
13320
13574
  winston2.format.printf(({ timestamp, level, message }) => {
13321
13575
  return `${timestamp} [${level}] ${message}`;
13322
13576
  })
13323
- ) : winston2.format.json()
13577
+ ) : winston2.format.combine(
13578
+ lineLimitFormat(),
13579
+ winston2.format.json()
13580
+ )
13324
13581
  });
13325
13582
  var formatArg = (arg) => typeof arg === "object" ? util.inspect(arg, { depth: null, colors: isDev }) : String(arg);
13326
13583
  var createLogMethod = (logger, logLevel) => {
@@ -13390,6 +13647,7 @@ var ExuluApp2 = class {
13390
13647
  this._tools = [
13391
13648
  ...tools ?? [],
13392
13649
  ...todoTools,
13650
+ ...questionTools,
13393
13651
  ...perplexityTools,
13394
13652
  // Add contexts as tools
13395
13653
  ...Object.values(contexts || {}).map((context) => context.tool()).filter(Boolean)
@@ -16174,7 +16432,7 @@ import * as path from "path";
16174
16432
  import { generateText as generateText3, Output as Output3 } from "ai";
16175
16433
  import { z as z13 } from "zod";
16176
16434
  import pLimit from "p-limit";
16177
- import { randomUUID as randomUUID6 } from "crypto";
16435
+ import { randomUUID as randomUUID7 } from "crypto";
16178
16436
  import * as mammoth from "mammoth";
16179
16437
  import TurndownService from "turndown";
16180
16438
  import WordExtractor from "word-extractor";
@@ -16872,7 +17130,7 @@ var loadFile = async (file, name, tempDir) => {
16872
17130
  if (!fileType) {
16873
17131
  throw new Error("[EXULU] File name does not include extension, extension is required for document processing.");
16874
17132
  }
16875
- const UUID = randomUUID6();
17133
+ const UUID = randomUUID7();
16876
17134
  let buffer;
16877
17135
  if (Buffer.isBuffer(file)) {
16878
17136
  filePath = path.join(tempDir, `${UUID}.${fileType}`);
@@ -16902,7 +17160,7 @@ async function documentProcessor({
16902
17160
  if (!license["advanced-document-processing"]) {
16903
17161
  throw new Error("Advanced document processing is an enterprise feature, please add a valid Exulu enterprise license key to use it.");
16904
17162
  }
16905
- const uuid = randomUUID6();
17163
+ const uuid = randomUUID7();
16906
17164
  const tempDir = path.join(process.cwd(), "temp", uuid);
16907
17165
  const localFilesAndFoldersToDelete = [tempDir];
16908
17166
  console.log(`[EXULU] Temporary directory for processing document ${name}: ${tempDir}`);
package/ee/workers.ts CHANGED
@@ -358,7 +358,33 @@ export const createWorkers = async (
358
358
 
359
359
  const exuluStorage = new ExuluStorage({ config });
360
360
 
361
- console.log("[EXULU] POS 2 -- EXULU CONTEXT PROCESS FIELD");
361
+ if (context.processor.filter) {
362
+ const result = await context.processor.filter({
363
+ item: data.inputs,
364
+ user: data.user,
365
+ role: data.role,
366
+ utils: {
367
+ storage: exuluStorage,
368
+ },
369
+ exuluConfig: config,
370
+ });
371
+
372
+ if (!result) {
373
+ console.log("[EXULU] Item filtered out by processor, skipping processing execution...");
374
+ return {
375
+ result: "Item filtered out by processor, skipping processing execution...", // last message
376
+ metadata: {
377
+ item: {
378
+ name: data.inputs?.name,
379
+ id: data.inputs?.id,
380
+ external_id: data.inputs?.external_id
381
+ }
382
+ },
383
+ };
384
+ }
385
+ }
386
+
387
+ console.log("[EXULU] POS 2 -- EXULU CONTEXT PROCESS FIELD", data.inputs);
362
388
  let processorResult = await context.processor.execute({
363
389
  item: data.inputs,
364
390
  user: data.user,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@exulu/backend",
3
3
  "author": "Qventu Bv.",
4
- "version": "1.52.0",
4
+ "version": "1.53.0",
5
5
  "main": "./dist/index.js",
6
6
  "private": false,
7
7
  "publishConfig": {
@@ -90,6 +90,7 @@
90
90
  "@ai-sdk/cerebras": "^2.0.29",
91
91
  "@ai-sdk/google-vertex": "^4.0.28",
92
92
  "@ai-sdk/openai": "^3.0.18",
93
+ "@ai-sdk/openai-compatible": "^2.0.37",
93
94
  "@anthropic-ai/sdk": "^0.56.0",
94
95
  "@apollo/server": "^5.4.0",
95
96
  "@as-integrations/express5": "^1.0.0",