@superatomai/sdk-node 0.0.57 → 0.0.59

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.mjs CHANGED
@@ -1620,6 +1620,7 @@ __export(utils_exports, {
1620
1620
  fixScalarSubqueries: () => fixScalarSubqueries,
1621
1621
  getDatabaseType: () => getDatabaseType,
1622
1622
  getJsonSizeInBytes: () => getJsonSizeInBytes,
1623
+ validateAndFixSqlQuery: () => validateAndFixSqlQuery,
1623
1624
  validateMessageSize: () => validateMessageSize
1624
1625
  });
1625
1626
  function getDatabaseType() {
@@ -1795,6 +1796,105 @@ function validateMessageSize(message, maxSize = 1048576) {
1795
1796
  maxSize
1796
1797
  };
1797
1798
  }
1799
+ function validateAndFixSqlQuery(query, dbType) {
1800
+ if (!query || query.trim().length === 0) {
1801
+ return { query, fixed: false, fixes: [] };
1802
+ }
1803
+ const databaseType = dbType || getDatabaseType();
1804
+ const _isMssql = databaseType === "mssql";
1805
+ let fixedQuery = query;
1806
+ const fixes = [];
1807
+ const aggregateFunctions = ["SUM", "COUNT", "AVG", "MIN", "MAX"];
1808
+ const aggregateInWherePattern = new RegExp(
1809
+ `\\bWHERE\\b[^]*?\\b(${aggregateFunctions.join("|")})\\s*\\([^)]*\\)\\s*(?:=|>|<|>=|<=|<>|!=)`,
1810
+ "i"
1811
+ );
1812
+ if (aggregateInWherePattern.test(fixedQuery)) {
1813
+ const aggregateConditionPattern = new RegExp(
1814
+ `\\s+(AND|OR)\\s+((?:COALESCE\\s*\\(\\s*)?(?:${aggregateFunctions.join("|")})\\s*\\([^)]+\\)[^)]*(?:\\))?\\s*(?:=|>|<|>=|<=|<>|!=)\\s*[^\\s,)]+)`,
1815
+ "gi"
1816
+ );
1817
+ const aggregateConditions = [];
1818
+ let match;
1819
+ while ((match = aggregateConditionPattern.exec(fixedQuery)) !== null) {
1820
+ aggregateConditions.push(match[2].trim());
1821
+ }
1822
+ if (aggregateConditions.length > 0) {
1823
+ fixedQuery = fixedQuery.replace(aggregateConditionPattern, "");
1824
+ fixedQuery = fixedQuery.replace(/\bWHERE\s+(AND|OR)\s+/gi, "WHERE ");
1825
+ fixedQuery = fixedQuery.replace(/\bWHERE\s+(GROUP\s+BY|ORDER\s+BY|HAVING|$)/gi, "$1");
1826
+ const hasGroupBy = /\bGROUP\s+BY\b/i.test(fixedQuery);
1827
+ if (hasGroupBy) {
1828
+ const hasHaving = /\bHAVING\b/i.test(fixedQuery);
1829
+ const havingClause = aggregateConditions.join(" AND ");
1830
+ if (hasHaving) {
1831
+ fixedQuery = fixedQuery.replace(
1832
+ /\bHAVING\b/i,
1833
+ `HAVING ${havingClause} AND`
1834
+ );
1835
+ } else {
1836
+ const orderByMatch = fixedQuery.match(/(\s+ORDER\s+BY\s+)/i);
1837
+ if (orderByMatch) {
1838
+ fixedQuery = fixedQuery.replace(
1839
+ orderByMatch[1],
1840
+ ` HAVING ${havingClause}${orderByMatch[1]}`
1841
+ );
1842
+ } else {
1843
+ fixedQuery = fixedQuery.trimEnd() + ` HAVING ${havingClause}`;
1844
+ }
1845
+ }
1846
+ fixes.push(`Moved aggregate condition(s) from WHERE to HAVING: ${havingClause}`);
1847
+ }
1848
+ }
1849
+ }
1850
+ let openCount = 0;
1851
+ let closeCount = 0;
1852
+ let inString = false;
1853
+ let stringChar = "";
1854
+ for (let i = 0; i < fixedQuery.length; i++) {
1855
+ const char = fixedQuery[i];
1856
+ const prevChar = i > 0 ? fixedQuery[i - 1] : "";
1857
+ if ((char === "'" || char === '"') && prevChar !== "\\") {
1858
+ if (!inString) {
1859
+ inString = true;
1860
+ stringChar = char;
1861
+ } else if (char === stringChar) {
1862
+ if (i + 1 < fixedQuery.length && fixedQuery[i + 1] === char) {
1863
+ i++;
1864
+ } else {
1865
+ inString = false;
1866
+ }
1867
+ }
1868
+ continue;
1869
+ }
1870
+ if (!inString) {
1871
+ if (char === "(") openCount++;
1872
+ else if (char === ")") closeCount++;
1873
+ }
1874
+ }
1875
+ if (openCount > closeCount) {
1876
+ const missingClose = openCount - closeCount;
1877
+ fixedQuery = fixedQuery.trimEnd();
1878
+ const hasSemicolon = fixedQuery.endsWith(";");
1879
+ if (hasSemicolon) {
1880
+ fixedQuery = fixedQuery.slice(0, -1);
1881
+ }
1882
+ fixedQuery = fixedQuery + ")".repeat(missingClose);
1883
+ if (hasSemicolon) {
1884
+ fixedQuery = fixedQuery + ";";
1885
+ }
1886
+ fixes.push(`Added ${missingClose} missing closing parenthesis(es)`);
1887
+ }
1888
+ const originalLength = fixedQuery.length;
1889
+ fixedQuery = fixedQuery.replace(/\s+/g, " ").trim();
1890
+ if (fixedQuery.length !== originalLength) {
1891
+ }
1892
+ return {
1893
+ query: fixedQuery,
1894
+ fixed: fixes.length > 0,
1895
+ fixes
1896
+ };
1897
+ }
1798
1898
  var init_utils = __esm({
1799
1899
  "src/userResponse/utils.ts"() {
1800
1900
  "use strict";
@@ -2359,8 +2459,14 @@ var BookmarksRequestMessageSchema = z3.object({
2359
2459
  type: z3.literal("BOOKMARKS"),
2360
2460
  payload: BookmarksRequestPayloadSchema
2361
2461
  });
2462
+ var ArtifactsQueryFiltersSchema = z3.object({
2463
+ createdBy: z3.number().optional(),
2464
+ status: z3.string().optional(),
2465
+ name: z3.string().optional(),
2466
+ deleted: z3.boolean().optional()
2467
+ });
2362
2468
  var ArtifactsRequestPayloadSchema = z3.object({
2363
- operation: z3.enum(["create", "update", "delete", "getAll", "getOne"]),
2469
+ operation: z3.enum(["create", "update", "delete", "getAll", "getOne", "query"]),
2364
2470
  data: z3.object({
2365
2471
  id: z3.number().optional(),
2366
2472
  name: z3.string().optional(),
@@ -2368,7 +2474,10 @@ var ArtifactsRequestPayloadSchema = z3.object({
2368
2474
  dsl: z3.record(z3.any()).optional(),
2369
2475
  status: z3.string().optional(),
2370
2476
  deleted: z3.boolean().optional(),
2371
- limit: z3.number().optional()
2477
+ limit: z3.number().optional(),
2478
+ // Query operation fields
2479
+ filters: ArtifactsQueryFiltersSchema.optional(),
2480
+ sort: z3.enum(["ASC", "DESC"]).optional()
2372
2481
  }).optional()
2373
2482
  });
2374
2483
  var ArtifactsRequestMessageSchema = z3.object({
@@ -5896,7 +6005,10 @@ var BaseLLM = class {
5896
6005
  * @param componentStreamCallback - Optional callback to stream primary KPI component as soon as it's identified
5897
6006
  * @returns Object containing matched components, layout title/description, and follow-up actions
5898
6007
  */
5899
- async matchComponentsFromAnalysis(analysisContent, components, apiKey, logCollector, componentStreamCallback, deferredTools, executedTools) {
6008
+ async matchComponentsFromAnalysis(analysisContent, components, apiKey, logCollector, componentStreamCallback, deferredTools, executedTools, collections, userId, userPrompt) {
6009
+ const methodStartTime = Date.now();
6010
+ const methodName = "matchComponentsFromAnalysis";
6011
+ logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("complex")}`);
5900
6012
  try {
5901
6013
  logger.debug(`[${this.getProviderName()}] Starting component matching from text response`);
5902
6014
  let availableComponentsText = "No components available";
@@ -5956,6 +6068,16 @@ ${fieldsText}`;
5956
6068
  }
5957
6069
  const schemaDoc = schema.generateSchemaDocumentation();
5958
6070
  const databaseRules = await promptLoader.loadDatabaseRules();
6071
+ let knowledgeBaseContext = "No additional knowledge base context available.";
6072
+ if (collections) {
6073
+ const kbResult = await knowledge_base_default.getAllKnowledgeBase({
6074
+ prompt: userPrompt || analysisContent,
6075
+ collections,
6076
+ userId,
6077
+ topK: 3
6078
+ });
6079
+ knowledgeBaseContext = kbResult.combinedContext || knowledgeBaseContext;
6080
+ }
5959
6081
  const prompts = await promptLoader.loadPrompts("match-text-components", {
5960
6082
  ANALYSIS_CONTENT: analysisContent,
5961
6083
  AVAILABLE_COMPONENTS: availableComponentsText,
@@ -5963,11 +6085,27 @@ ${fieldsText}`;
5963
6085
  DATABASE_RULES: databaseRules,
5964
6086
  DEFERRED_TOOLS: deferredToolsText,
5965
6087
  EXECUTED_TOOLS: executedToolsText,
6088
+ KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext,
5966
6089
  CURRENT_DATETIME: getCurrentDateTimeForPrompt()
5967
6090
  });
5968
6091
  logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
5969
- const systemPromptStr = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
5970
- logger.logLLMPrompt("matchComponentsFromAnalysis", "system", systemPromptStr);
6092
+ const extractPromptText = (content) => {
6093
+ if (typeof content === "string") return content;
6094
+ if (Array.isArray(content)) {
6095
+ return content.map((item) => {
6096
+ if (typeof item === "string") return item;
6097
+ if (item && typeof item.text === "string") return item.text;
6098
+ if (item && item.content && typeof item.content === "string") return item.content;
6099
+ return JSON.stringify(item, null, 2);
6100
+ }).join("\n\n---\n\n");
6101
+ }
6102
+ if (content && typeof content === "object") {
6103
+ if (typeof content.text === "string") return content.text;
6104
+ return JSON.stringify(content, null, 2);
6105
+ }
6106
+ return String(content);
6107
+ };
6108
+ logger.logLLMPrompt("matchComponentsFromAnalysis", "system", extractPromptText(prompts.system));
5971
6109
  logger.logLLMPrompt("matchComponentsFromAnalysis", "user", `Text Analysis:
5972
6110
  ${analysisContent}
5973
6111
 
@@ -6192,6 +6330,18 @@ ${executedToolsText}`);
6192
6330
  cleanedProps.query = null;
6193
6331
  }
6194
6332
  }
6333
+ if (cleanedProps.query) {
6334
+ const queryStr = typeof cleanedProps.query === "string" ? cleanedProps.query : cleanedProps.query?.sql || "";
6335
+ const { query: fixedQuery, fixed, fixes } = validateAndFixSqlQuery(queryStr);
6336
+ if (fixed) {
6337
+ logger.warn(`[${this.getProviderName()}] SQL fixes applied to component query: ${fixes.join("; ")}`);
6338
+ if (typeof cleanedProps.query === "string") {
6339
+ cleanedProps.query = fixedQuery;
6340
+ } else if (cleanedProps.query?.sql) {
6341
+ cleanedProps.query.sql = fixedQuery;
6342
+ }
6343
+ }
6344
+ }
6195
6345
  if (cleanedProps.query && cleanedProps.externalTool) {
6196
6346
  logger.info(`[${this.getProviderName()}] Both query and externalTool exist, keeping both - frontend will decide`);
6197
6347
  }
@@ -6203,6 +6353,8 @@ ${executedToolsText}`);
6203
6353
  }
6204
6354
  };
6205
6355
  }).filter(Boolean);
6356
+ const methodDuration = Date.now() - methodStartTime;
6357
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | components: ${finalComponents.length} | actions: ${actions.length}`);
6206
6358
  return {
6207
6359
  components: finalComponents,
6208
6360
  layoutTitle,
@@ -6210,8 +6362,9 @@ ${executedToolsText}`);
6210
6362
  actions
6211
6363
  };
6212
6364
  } catch (error) {
6365
+ const methodDuration = Date.now() - methodStartTime;
6213
6366
  const errorMsg = error instanceof Error ? error.message : String(error);
6214
- logger.error(`[${this.getProviderName()}] Error matching components: ${errorMsg}`);
6367
+ logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
6215
6368
  logCollector?.error(`Failed to match components: ${errorMsg}`);
6216
6369
  return {
6217
6370
  components: [],
@@ -6226,6 +6379,10 @@ ${executedToolsText}`);
6226
6379
  * Determines if question is for data analysis, requires external tools, or needs text response
6227
6380
  */
6228
6381
  async classifyQuestionCategory(userPrompt, apiKey, logCollector, conversationHistory, externalTools) {
6382
+ const methodStartTime = Date.now();
6383
+ const methodName = "classifyQuestionCategory";
6384
+ const promptPreview = userPrompt.substring(0, 50) + (userPrompt.length > 50 ? "..." : "");
6385
+ logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("simple")} | prompt: "${promptPreview}"`);
6229
6386
  try {
6230
6387
  const schemaDoc = schema.generateSchemaDocumentation();
6231
6388
  const availableToolsDoc = externalTools && externalTools.length > 0 ? externalTools.map((tool) => {
@@ -6241,10 +6398,24 @@ ${executedToolsText}`);
6241
6398
  SCHEMA_DOC: schemaDoc || "No database schema available",
6242
6399
  CURRENT_DATETIME: getCurrentDateTimeForPrompt()
6243
6400
  });
6244
- const systemPrompt = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
6245
- const userPromptText = Array.isArray(prompts.user) ? prompts.user.join("\n") : prompts.user;
6246
- logger.logLLMPrompt("classifyQuestionCategory", "system", systemPrompt);
6247
- logger.logLLMPrompt("classifyQuestionCategory", "user", userPromptText);
6401
+ const extractTextContent = (content) => {
6402
+ if (typeof content === "string") return content;
6403
+ if (Array.isArray(content)) {
6404
+ return content.map((item) => {
6405
+ if (typeof item === "string") return item;
6406
+ if (item && typeof item.text === "string") return item.text;
6407
+ if (item && item.content && typeof item.content === "string") return item.content;
6408
+ return JSON.stringify(item, null, 2);
6409
+ }).join("\n\n---\n\n");
6410
+ }
6411
+ if (content && typeof content === "object") {
6412
+ if (typeof content.text === "string") return content.text;
6413
+ return JSON.stringify(content, null, 2);
6414
+ }
6415
+ return String(content);
6416
+ };
6417
+ logger.logLLMPrompt("classifyQuestionCategory", "system", extractTextContent(prompts.system));
6418
+ logger.logLLMPrompt("classifyQuestionCategory", "user", extractTextContent(prompts.user));
6248
6419
  const result = await LLM.stream(
6249
6420
  {
6250
6421
  sys: prompts.system,
@@ -6269,6 +6440,8 @@ ${executedToolsText}`);
6269
6440
  confidence: result.confidence
6270
6441
  }
6271
6442
  );
6443
+ const methodDuration = Date.now() - methodStartTime;
6444
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | category: ${result.category} | confidence: ${result.confidence}% | tools: ${(result.externalTools || []).length}`);
6272
6445
  return {
6273
6446
  category: result.category || "data_analysis",
6274
6447
  externalTools: result.externalTools || [],
@@ -6277,8 +6450,9 @@ ${executedToolsText}`);
6277
6450
  confidence: result.confidence || 0
6278
6451
  };
6279
6452
  } catch (error) {
6453
+ const methodDuration = Date.now() - methodStartTime;
6280
6454
  const errorMsg = error instanceof Error ? error.message : String(error);
6281
- logger.error(`[${this.getProviderName()}] Error classifying question category: ${errorMsg}`);
6455
+ logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
6282
6456
  logger.debug(`[${this.getProviderName()}] Category classification error details:`, error);
6283
6457
  throw error;
6284
6458
  }
@@ -6289,9 +6463,15 @@ ${executedToolsText}`);
6289
6463
  * Also adapts the cached text response to match the new question
6290
6464
  */
6291
6465
  async adaptUIBlockParameters(currentUserPrompt, originalUserPrompt, matchedUIBlock, apiKey, logCollector, cachedTextResponse) {
6466
+ const methodStartTime = Date.now();
6467
+ const methodName = "adaptUIBlockParameters";
6468
+ const promptPreview = currentUserPrompt.substring(0, 50) + (currentUserPrompt.length > 50 ? "..." : "");
6469
+ logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("complex")} | prompt: "${promptPreview}"`);
6292
6470
  try {
6293
6471
  const component = matchedUIBlock?.generatedComponentMetadata || matchedUIBlock?.component;
6294
6472
  if (!matchedUIBlock || !component) {
6473
+ const methodDuration2 = Date.now() - methodStartTime;
6474
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration2}ms | result: no component found`);
6295
6475
  return {
6296
6476
  success: false,
6297
6477
  explanation: "No component found in matched UI block"
@@ -6324,9 +6504,8 @@ ${executedToolsText}`);
6324
6504
  // Parse as JSON
6325
6505
  );
6326
6506
  if (!result.success) {
6327
- logger.info(
6328
- `[${this.getProviderName()}] Could not adapt UI block: ${result.reason}`
6329
- );
6507
+ const methodDuration2 = Date.now() - methodStartTime;
6508
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration2}ms | result: adaptation failed - ${result.reason}`);
6330
6509
  logCollector?.warn(
6331
6510
  "Could not adapt matched UI block",
6332
6511
  "explanation",
@@ -6351,6 +6530,8 @@ ${executedToolsText}`);
6351
6530
  componentType: result.adaptedComponent?.type
6352
6531
  }
6353
6532
  );
6533
+ const methodDuration = Date.now() - methodStartTime;
6534
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | result: success | changes: ${(result.parametersChanged || []).length}`);
6354
6535
  return {
6355
6536
  success: true,
6356
6537
  adaptedComponent: result.adaptedComponent,
@@ -6359,8 +6540,9 @@ ${executedToolsText}`);
6359
6540
  explanation: result.explanation || "Parameters adapted successfully"
6360
6541
  };
6361
6542
  } catch (error) {
6543
+ const methodDuration = Date.now() - methodStartTime;
6362
6544
  const errorMsg = error instanceof Error ? error.message : String(error);
6363
- logger.error(`[${this.getProviderName()}] Error adapting UI block parameters: ${errorMsg}`);
6545
+ logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
6364
6546
  logger.debug(`[${this.getProviderName()}] Adaptation error details:`, error);
6365
6547
  return {
6366
6548
  success: false,
@@ -6381,6 +6563,10 @@ ${executedToolsText}`);
6381
6563
  * @param userId - Optional user ID for fetching user-specific knowledge base nodes
6382
6564
  */
6383
6565
  async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory, streamCallback, collections, components, externalTools, category, userId) {
6566
+ const methodStartTime = Date.now();
6567
+ const methodName = "generateTextResponse";
6568
+ const promptPreview = userPrompt.substring(0, 50) + (userPrompt.length > 50 ? "..." : "");
6569
+ logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("complex")} | category: ${category} | prompt: "${promptPreview}"`);
6384
6570
  const errors = [];
6385
6571
  logger.debug(`[${this.getProviderName()}] Starting text response generation`);
6386
6572
  logger.debug(`[${this.getProviderName()}] User prompt: "${userPrompt.substring(0, 50)}..."`);
@@ -6445,10 +6631,24 @@ ${executedToolsText}`);
6445
6631
  AVAILABLE_EXTERNAL_TOOLS: availableToolsDoc,
6446
6632
  CURRENT_DATETIME: getCurrentDateTimeForPrompt()
6447
6633
  });
6448
- const sysPrompt = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
6449
- const usrPrompt = Array.isArray(prompts.user) ? prompts.user.join("\n") : prompts.user;
6450
- logger.logLLMPrompt("generateTextResponse", "system", sysPrompt);
6451
- logger.logLLMPrompt("generateTextResponse", "user", usrPrompt);
6634
+ const extractText = (content) => {
6635
+ if (typeof content === "string") return content;
6636
+ if (Array.isArray(content)) {
6637
+ return content.map((item) => {
6638
+ if (typeof item === "string") return item;
6639
+ if (item && typeof item.text === "string") return item.text;
6640
+ if (item && item.content && typeof item.content === "string") return item.content;
6641
+ return JSON.stringify(item, null, 2);
6642
+ }).join("\n\n---\n\n");
6643
+ }
6644
+ if (content && typeof content === "object") {
6645
+ if (typeof content.text === "string") return content.text;
6646
+ return JSON.stringify(content, null, 2);
6647
+ }
6648
+ return String(content);
6649
+ };
6650
+ logger.logLLMPrompt("generateTextResponse", "system", extractText(prompts.system));
6651
+ logger.logLLMPrompt("generateTextResponse", "user", extractText(prompts.user));
6452
6652
  logger.debug(`[${this.getProviderName()}] Loaded text-response prompts with schema`);
6453
6653
  logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
6454
6654
  logCollector?.info("Generating text response with query execution capability...");
@@ -6894,7 +7094,8 @@ ${errorMsg}
6894
7094
  logger.info(`[${this.getProviderName()}] Text response stream completed`);
6895
7095
  const textResponse = fullStreamedText || result || "I apologize, but I was unable to generate a response.";
6896
7096
  if (maxAttemptsReached) {
6897
- logger.warn(`[${this.getProviderName()}] Max query attempts reached, returning failure response`);
7097
+ const methodDuration2 = Date.now() - methodStartTime;
7098
+ logger.warn(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration2}ms | result: max attempts reached`);
6898
7099
  logCollector?.error("Failed to generate valid query after maximum attempts");
6899
7100
  return {
6900
7101
  success: false,
@@ -6971,7 +7172,10 @@ ${errorMsg}
6971
7172
  logCollector,
6972
7173
  componentStreamCallback,
6973
7174
  deferredTools,
6974
- executedToolsList
7175
+ executedToolsList,
7176
+ collections,
7177
+ userId,
7178
+ userPrompt
6975
7179
  );
6976
7180
  matchedComponents = matchResult.components;
6977
7181
  layoutTitle = matchResult.layoutTitle;
@@ -6997,6 +7201,8 @@ ${errorMsg}
6997
7201
  }
6998
7202
  };
6999
7203
  }
7204
+ const methodDuration = Date.now() - methodStartTime;
7205
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | result: success | components: ${matchedComponents.length} | actions: ${actions.length}`);
7000
7206
  return {
7001
7207
  success: true,
7002
7208
  data: {
@@ -7008,8 +7214,9 @@ ${errorMsg}
7008
7214
  errors: []
7009
7215
  };
7010
7216
  } catch (error) {
7217
+ const methodDuration = Date.now() - methodStartTime;
7011
7218
  const errorMsg = error instanceof Error ? error.message : String(error);
7012
- logger.error(`[${this.getProviderName()}] Error generating text response: ${errorMsg}`);
7219
+ logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
7013
7220
  logCollector?.error(`Error generating text response: ${errorMsg}`);
7014
7221
  userPromptErrorLogger.logLlmError(
7015
7222
  this.getProviderName(),
@@ -7051,7 +7258,6 @@ ${errorMsg}
7051
7258
  logger.logLLMPrompt("handleUserRequest", "user", `User Prompt: ${userPrompt}`);
7052
7259
  try {
7053
7260
  logger.info(`[${this.getProviderName()}] Step 1: Searching previous conversations...`);
7054
- logCollector?.info("Step 1: Searching for similar previous conversations...");
7055
7261
  const conversationMatch = await conversation_search_default.searchConversationsWithReranking({
7056
7262
  userPrompt,
7057
7263
  collections,
@@ -7263,6 +7469,10 @@ ${errorMsg}
7263
7469
  * For general/conversational questions without components, pass textResponse instead
7264
7470
  */
7265
7471
  async generateNextQuestions(originalUserPrompt, component, componentData, apiKey, logCollector, conversationHistory, textResponse) {
7472
+ const methodStartTime = Date.now();
7473
+ const methodName = "generateNextQuestions";
7474
+ const promptPreview = originalUserPrompt.substring(0, 50) + (originalUserPrompt.length > 50 ? "..." : "");
7475
+ logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("simple")} | prompt: "${promptPreview}"`);
7266
7476
  try {
7267
7477
  let component_info;
7268
7478
  if (component) {
@@ -7311,10 +7521,13 @@ ${errorMsg}
7311
7521
  questions: nextQuestions
7312
7522
  }
7313
7523
  );
7524
+ const methodDuration = Date.now() - methodStartTime;
7525
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | questions: ${nextQuestions.length}`);
7314
7526
  return nextQuestions;
7315
7527
  } catch (error) {
7528
+ const methodDuration = Date.now() - methodStartTime;
7316
7529
  const errorMsg = error instanceof Error ? error.message : String(error);
7317
- logger.error(`[${this.getProviderName()}] Error generating next questions: ${errorMsg}`);
7530
+ logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
7318
7531
  logger.debug(`[${this.getProviderName()}] Next questions generation error details:`, error);
7319
7532
  logCollector?.error(`Error generating next questions: ${errorMsg}`);
7320
7533
  return [];
@@ -10322,6 +10535,8 @@ async function handleArtifactsRequest(data, collections, sendMessage) {
10322
10535
  const status = requestData?.status;
10323
10536
  const deleted = requestData?.deleted;
10324
10537
  const limit = requestData?.limit;
10538
+ const filters = requestData?.filters;
10539
+ const sort = requestData?.sort;
10325
10540
  switch (operation) {
10326
10541
  case "create":
10327
10542
  await handleCreate6(id, name, createdBy, dsl, status, executeCollection, sendMessage, from.id);
@@ -10338,6 +10553,9 @@ async function handleArtifactsRequest(data, collections, sendMessage) {
10338
10553
  case "getOne":
10339
10554
  await handleGetOne6(id, artifactId, executeCollection, sendMessage, from.id);
10340
10555
  break;
10556
+ case "query":
10557
+ await handleQuery6(id, { filters, limit, sort }, executeCollection, sendMessage, from.id);
10558
+ break;
10341
10559
  default:
10342
10560
  sendResponse8(id, {
10343
10561
  success: false,
@@ -10461,6 +10679,27 @@ async function handleGetOne6(id, artifactId, executeCollection, sendMessage, cli
10461
10679
  }, sendMessage, clientId);
10462
10680
  }
10463
10681
  }
10682
+ async function handleQuery6(id, queryParams, executeCollection, sendMessage, clientId) {
10683
+ try {
10684
+ const result = await executeCollection("artifacts", "query", {
10685
+ filters: queryParams.filters,
10686
+ limit: queryParams.limit || 50,
10687
+ sort: queryParams.sort || "DESC"
10688
+ });
10689
+ sendResponse8(id, {
10690
+ success: true,
10691
+ data: result.data,
10692
+ count: result.count,
10693
+ message: `Query returned ${result.count} artifacts`
10694
+ }, sendMessage, clientId);
10695
+ logger.info(`Query artifacts (count: ${result.count})`);
10696
+ } catch (error) {
10697
+ sendResponse8(id, {
10698
+ success: false,
10699
+ error: error instanceof Error ? error.message : "Failed to query artifacts"
10700
+ }, sendMessage, clientId);
10701
+ }
10702
+ }
10464
10703
  function sendResponse8(id, res, sendMessage, clientId) {
10465
10704
  const response = {
10466
10705
  id: id || "unknown",
@@ -10987,7 +11226,7 @@ async function handleMenusRequest(data, collections, sendMessage) {
10987
11226
  await handleGetHierarchy(id, executeCollection, sendMessage, from.id);
10988
11227
  break;
10989
11228
  case "query":
10990
- await handleQuery6(id, filters, limit, sort, executeCollection, sendMessage, from.id);
11229
+ await handleQuery7(id, filters, limit, sort, executeCollection, sendMessage, from.id);
10991
11230
  break;
10992
11231
  case "reorder":
10993
11232
  await handleReorder(id, items, executeCollection, sendMessage, from.id);
@@ -11199,7 +11438,7 @@ async function handleGetHierarchy(id, executeCollection, sendMessage, clientId)
11199
11438
  }, sendMessage, clientId);
11200
11439
  }
11201
11440
  }
11202
- async function handleQuery6(id, filters, limit, sort, executeCollection, sendMessage, clientId) {
11441
+ async function handleQuery7(id, filters, limit, sort, executeCollection, sendMessage, clientId) {
11203
11442
  try {
11204
11443
  const result = await executeCollection("menus", "query", {
11205
11444
  filters: filters || {},