@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.d.mts CHANGED
@@ -2097,7 +2097,7 @@ declare abstract class BaseLLM {
2097
2097
  * @param componentStreamCallback - Optional callback to stream primary KPI component as soon as it's identified
2098
2098
  * @returns Object containing matched components, layout title/description, and follow-up actions
2099
2099
  */
2100
- matchComponentsFromAnalysis(analysisContent: string, components: Component[], apiKey?: string, logCollector?: any, componentStreamCallback?: (component: Component) => void, deferredTools?: any[], executedTools?: any[]): Promise<{
2100
+ matchComponentsFromAnalysis(analysisContent: string, components: Component[], apiKey?: string, logCollector?: any, componentStreamCallback?: (component: Component) => void, deferredTools?: any[], executedTools?: any[], collections?: any, userId?: string, userPrompt?: string): Promise<{
2101
2101
  components: Component[];
2102
2102
  layoutTitle: string;
2103
2103
  layoutDescription: string;
package/dist/index.d.ts CHANGED
@@ -2097,7 +2097,7 @@ declare abstract class BaseLLM {
2097
2097
  * @param componentStreamCallback - Optional callback to stream primary KPI component as soon as it's identified
2098
2098
  * @returns Object containing matched components, layout title/description, and follow-up actions
2099
2099
  */
2100
- matchComponentsFromAnalysis(analysisContent: string, components: Component[], apiKey?: string, logCollector?: any, componentStreamCallback?: (component: Component) => void, deferredTools?: any[], executedTools?: any[]): Promise<{
2100
+ matchComponentsFromAnalysis(analysisContent: string, components: Component[], apiKey?: string, logCollector?: any, componentStreamCallback?: (component: Component) => void, deferredTools?: any[], executedTools?: any[], collections?: any, userId?: string, userPrompt?: string): Promise<{
2101
2101
  components: Component[];
2102
2102
  layoutTitle: string;
2103
2103
  layoutDescription: string;
package/dist/index.js CHANGED
@@ -1642,6 +1642,7 @@ __export(utils_exports, {
1642
1642
  fixScalarSubqueries: () => fixScalarSubqueries,
1643
1643
  getDatabaseType: () => getDatabaseType,
1644
1644
  getJsonSizeInBytes: () => getJsonSizeInBytes,
1645
+ validateAndFixSqlQuery: () => validateAndFixSqlQuery,
1645
1646
  validateMessageSize: () => validateMessageSize
1646
1647
  });
1647
1648
  function getDatabaseType() {
@@ -1817,6 +1818,105 @@ function validateMessageSize(message, maxSize = 1048576) {
1817
1818
  maxSize
1818
1819
  };
1819
1820
  }
1821
+ function validateAndFixSqlQuery(query, dbType) {
1822
+ if (!query || query.trim().length === 0) {
1823
+ return { query, fixed: false, fixes: [] };
1824
+ }
1825
+ const databaseType = dbType || getDatabaseType();
1826
+ const _isMssql = databaseType === "mssql";
1827
+ let fixedQuery = query;
1828
+ const fixes = [];
1829
+ const aggregateFunctions = ["SUM", "COUNT", "AVG", "MIN", "MAX"];
1830
+ const aggregateInWherePattern = new RegExp(
1831
+ `\\bWHERE\\b[^]*?\\b(${aggregateFunctions.join("|")})\\s*\\([^)]*\\)\\s*(?:=|>|<|>=|<=|<>|!=)`,
1832
+ "i"
1833
+ );
1834
+ if (aggregateInWherePattern.test(fixedQuery)) {
1835
+ const aggregateConditionPattern = new RegExp(
1836
+ `\\s+(AND|OR)\\s+((?:COALESCE\\s*\\(\\s*)?(?:${aggregateFunctions.join("|")})\\s*\\([^)]+\\)[^)]*(?:\\))?\\s*(?:=|>|<|>=|<=|<>|!=)\\s*[^\\s,)]+)`,
1837
+ "gi"
1838
+ );
1839
+ const aggregateConditions = [];
1840
+ let match;
1841
+ while ((match = aggregateConditionPattern.exec(fixedQuery)) !== null) {
1842
+ aggregateConditions.push(match[2].trim());
1843
+ }
1844
+ if (aggregateConditions.length > 0) {
1845
+ fixedQuery = fixedQuery.replace(aggregateConditionPattern, "");
1846
+ fixedQuery = fixedQuery.replace(/\bWHERE\s+(AND|OR)\s+/gi, "WHERE ");
1847
+ fixedQuery = fixedQuery.replace(/\bWHERE\s+(GROUP\s+BY|ORDER\s+BY|HAVING|$)/gi, "$1");
1848
+ const hasGroupBy = /\bGROUP\s+BY\b/i.test(fixedQuery);
1849
+ if (hasGroupBy) {
1850
+ const hasHaving = /\bHAVING\b/i.test(fixedQuery);
1851
+ const havingClause = aggregateConditions.join(" AND ");
1852
+ if (hasHaving) {
1853
+ fixedQuery = fixedQuery.replace(
1854
+ /\bHAVING\b/i,
1855
+ `HAVING ${havingClause} AND`
1856
+ );
1857
+ } else {
1858
+ const orderByMatch = fixedQuery.match(/(\s+ORDER\s+BY\s+)/i);
1859
+ if (orderByMatch) {
1860
+ fixedQuery = fixedQuery.replace(
1861
+ orderByMatch[1],
1862
+ ` HAVING ${havingClause}${orderByMatch[1]}`
1863
+ );
1864
+ } else {
1865
+ fixedQuery = fixedQuery.trimEnd() + ` HAVING ${havingClause}`;
1866
+ }
1867
+ }
1868
+ fixes.push(`Moved aggregate condition(s) from WHERE to HAVING: ${havingClause}`);
1869
+ }
1870
+ }
1871
+ }
1872
+ let openCount = 0;
1873
+ let closeCount = 0;
1874
+ let inString = false;
1875
+ let stringChar = "";
1876
+ for (let i = 0; i < fixedQuery.length; i++) {
1877
+ const char = fixedQuery[i];
1878
+ const prevChar = i > 0 ? fixedQuery[i - 1] : "";
1879
+ if ((char === "'" || char === '"') && prevChar !== "\\") {
1880
+ if (!inString) {
1881
+ inString = true;
1882
+ stringChar = char;
1883
+ } else if (char === stringChar) {
1884
+ if (i + 1 < fixedQuery.length && fixedQuery[i + 1] === char) {
1885
+ i++;
1886
+ } else {
1887
+ inString = false;
1888
+ }
1889
+ }
1890
+ continue;
1891
+ }
1892
+ if (!inString) {
1893
+ if (char === "(") openCount++;
1894
+ else if (char === ")") closeCount++;
1895
+ }
1896
+ }
1897
+ if (openCount > closeCount) {
1898
+ const missingClose = openCount - closeCount;
1899
+ fixedQuery = fixedQuery.trimEnd();
1900
+ const hasSemicolon = fixedQuery.endsWith(";");
1901
+ if (hasSemicolon) {
1902
+ fixedQuery = fixedQuery.slice(0, -1);
1903
+ }
1904
+ fixedQuery = fixedQuery + ")".repeat(missingClose);
1905
+ if (hasSemicolon) {
1906
+ fixedQuery = fixedQuery + ";";
1907
+ }
1908
+ fixes.push(`Added ${missingClose} missing closing parenthesis(es)`);
1909
+ }
1910
+ const originalLength = fixedQuery.length;
1911
+ fixedQuery = fixedQuery.replace(/\s+/g, " ").trim();
1912
+ if (fixedQuery.length !== originalLength) {
1913
+ }
1914
+ return {
1915
+ query: fixedQuery,
1916
+ fixed: fixes.length > 0,
1917
+ fixes
1918
+ };
1919
+ }
1820
1920
  var init_utils = __esm({
1821
1921
  "src/userResponse/utils.ts"() {
1822
1922
  "use strict";
@@ -2409,8 +2509,14 @@ var BookmarksRequestMessageSchema = import_zod3.z.object({
2409
2509
  type: import_zod3.z.literal("BOOKMARKS"),
2410
2510
  payload: BookmarksRequestPayloadSchema
2411
2511
  });
2512
+ var ArtifactsQueryFiltersSchema = import_zod3.z.object({
2513
+ createdBy: import_zod3.z.number().optional(),
2514
+ status: import_zod3.z.string().optional(),
2515
+ name: import_zod3.z.string().optional(),
2516
+ deleted: import_zod3.z.boolean().optional()
2517
+ });
2412
2518
  var ArtifactsRequestPayloadSchema = import_zod3.z.object({
2413
- operation: import_zod3.z.enum(["create", "update", "delete", "getAll", "getOne"]),
2519
+ operation: import_zod3.z.enum(["create", "update", "delete", "getAll", "getOne", "query"]),
2414
2520
  data: import_zod3.z.object({
2415
2521
  id: import_zod3.z.number().optional(),
2416
2522
  name: import_zod3.z.string().optional(),
@@ -2418,7 +2524,10 @@ var ArtifactsRequestPayloadSchema = import_zod3.z.object({
2418
2524
  dsl: import_zod3.z.record(import_zod3.z.any()).optional(),
2419
2525
  status: import_zod3.z.string().optional(),
2420
2526
  deleted: import_zod3.z.boolean().optional(),
2421
- limit: import_zod3.z.number().optional()
2527
+ limit: import_zod3.z.number().optional(),
2528
+ // Query operation fields
2529
+ filters: ArtifactsQueryFiltersSchema.optional(),
2530
+ sort: import_zod3.z.enum(["ASC", "DESC"]).optional()
2422
2531
  }).optional()
2423
2532
  });
2424
2533
  var ArtifactsRequestMessageSchema = import_zod3.z.object({
@@ -5946,7 +6055,10 @@ var BaseLLM = class {
5946
6055
  * @param componentStreamCallback - Optional callback to stream primary KPI component as soon as it's identified
5947
6056
  * @returns Object containing matched components, layout title/description, and follow-up actions
5948
6057
  */
5949
- async matchComponentsFromAnalysis(analysisContent, components, apiKey, logCollector, componentStreamCallback, deferredTools, executedTools) {
6058
+ async matchComponentsFromAnalysis(analysisContent, components, apiKey, logCollector, componentStreamCallback, deferredTools, executedTools, collections, userId, userPrompt) {
6059
+ const methodStartTime = Date.now();
6060
+ const methodName = "matchComponentsFromAnalysis";
6061
+ logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("complex")}`);
5950
6062
  try {
5951
6063
  logger.debug(`[${this.getProviderName()}] Starting component matching from text response`);
5952
6064
  let availableComponentsText = "No components available";
@@ -6006,6 +6118,16 @@ ${fieldsText}`;
6006
6118
  }
6007
6119
  const schemaDoc = schema.generateSchemaDocumentation();
6008
6120
  const databaseRules = await promptLoader.loadDatabaseRules();
6121
+ let knowledgeBaseContext = "No additional knowledge base context available.";
6122
+ if (collections) {
6123
+ const kbResult = await knowledge_base_default.getAllKnowledgeBase({
6124
+ prompt: userPrompt || analysisContent,
6125
+ collections,
6126
+ userId,
6127
+ topK: 3
6128
+ });
6129
+ knowledgeBaseContext = kbResult.combinedContext || knowledgeBaseContext;
6130
+ }
6009
6131
  const prompts = await promptLoader.loadPrompts("match-text-components", {
6010
6132
  ANALYSIS_CONTENT: analysisContent,
6011
6133
  AVAILABLE_COMPONENTS: availableComponentsText,
@@ -6013,11 +6135,27 @@ ${fieldsText}`;
6013
6135
  DATABASE_RULES: databaseRules,
6014
6136
  DEFERRED_TOOLS: deferredToolsText,
6015
6137
  EXECUTED_TOOLS: executedToolsText,
6138
+ KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext,
6016
6139
  CURRENT_DATETIME: getCurrentDateTimeForPrompt()
6017
6140
  });
6018
6141
  logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
6019
- const systemPromptStr = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
6020
- logger.logLLMPrompt("matchComponentsFromAnalysis", "system", systemPromptStr);
6142
+ const extractPromptText = (content) => {
6143
+ if (typeof content === "string") return content;
6144
+ if (Array.isArray(content)) {
6145
+ return content.map((item) => {
6146
+ if (typeof item === "string") return item;
6147
+ if (item && typeof item.text === "string") return item.text;
6148
+ if (item && item.content && typeof item.content === "string") return item.content;
6149
+ return JSON.stringify(item, null, 2);
6150
+ }).join("\n\n---\n\n");
6151
+ }
6152
+ if (content && typeof content === "object") {
6153
+ if (typeof content.text === "string") return content.text;
6154
+ return JSON.stringify(content, null, 2);
6155
+ }
6156
+ return String(content);
6157
+ };
6158
+ logger.logLLMPrompt("matchComponentsFromAnalysis", "system", extractPromptText(prompts.system));
6021
6159
  logger.logLLMPrompt("matchComponentsFromAnalysis", "user", `Text Analysis:
6022
6160
  ${analysisContent}
6023
6161
 
@@ -6242,6 +6380,18 @@ ${executedToolsText}`);
6242
6380
  cleanedProps.query = null;
6243
6381
  }
6244
6382
  }
6383
+ if (cleanedProps.query) {
6384
+ const queryStr = typeof cleanedProps.query === "string" ? cleanedProps.query : cleanedProps.query?.sql || "";
6385
+ const { query: fixedQuery, fixed, fixes } = validateAndFixSqlQuery(queryStr);
6386
+ if (fixed) {
6387
+ logger.warn(`[${this.getProviderName()}] SQL fixes applied to component query: ${fixes.join("; ")}`);
6388
+ if (typeof cleanedProps.query === "string") {
6389
+ cleanedProps.query = fixedQuery;
6390
+ } else if (cleanedProps.query?.sql) {
6391
+ cleanedProps.query.sql = fixedQuery;
6392
+ }
6393
+ }
6394
+ }
6245
6395
  if (cleanedProps.query && cleanedProps.externalTool) {
6246
6396
  logger.info(`[${this.getProviderName()}] Both query and externalTool exist, keeping both - frontend will decide`);
6247
6397
  }
@@ -6253,6 +6403,8 @@ ${executedToolsText}`);
6253
6403
  }
6254
6404
  };
6255
6405
  }).filter(Boolean);
6406
+ const methodDuration = Date.now() - methodStartTime;
6407
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | components: ${finalComponents.length} | actions: ${actions.length}`);
6256
6408
  return {
6257
6409
  components: finalComponents,
6258
6410
  layoutTitle,
@@ -6260,8 +6412,9 @@ ${executedToolsText}`);
6260
6412
  actions
6261
6413
  };
6262
6414
  } catch (error) {
6415
+ const methodDuration = Date.now() - methodStartTime;
6263
6416
  const errorMsg = error instanceof Error ? error.message : String(error);
6264
- logger.error(`[${this.getProviderName()}] Error matching components: ${errorMsg}`);
6417
+ logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
6265
6418
  logCollector?.error(`Failed to match components: ${errorMsg}`);
6266
6419
  return {
6267
6420
  components: [],
@@ -6276,6 +6429,10 @@ ${executedToolsText}`);
6276
6429
  * Determines if question is for data analysis, requires external tools, or needs text response
6277
6430
  */
6278
6431
  async classifyQuestionCategory(userPrompt, apiKey, logCollector, conversationHistory, externalTools) {
6432
+ const methodStartTime = Date.now();
6433
+ const methodName = "classifyQuestionCategory";
6434
+ const promptPreview = userPrompt.substring(0, 50) + (userPrompt.length > 50 ? "..." : "");
6435
+ logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("simple")} | prompt: "${promptPreview}"`);
6279
6436
  try {
6280
6437
  const schemaDoc = schema.generateSchemaDocumentation();
6281
6438
  const availableToolsDoc = externalTools && externalTools.length > 0 ? externalTools.map((tool) => {
@@ -6291,10 +6448,24 @@ ${executedToolsText}`);
6291
6448
  SCHEMA_DOC: schemaDoc || "No database schema available",
6292
6449
  CURRENT_DATETIME: getCurrentDateTimeForPrompt()
6293
6450
  });
6294
- const systemPrompt = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
6295
- const userPromptText = Array.isArray(prompts.user) ? prompts.user.join("\n") : prompts.user;
6296
- logger.logLLMPrompt("classifyQuestionCategory", "system", systemPrompt);
6297
- logger.logLLMPrompt("classifyQuestionCategory", "user", userPromptText);
6451
+ const extractTextContent = (content) => {
6452
+ if (typeof content === "string") return content;
6453
+ if (Array.isArray(content)) {
6454
+ return content.map((item) => {
6455
+ if (typeof item === "string") return item;
6456
+ if (item && typeof item.text === "string") return item.text;
6457
+ if (item && item.content && typeof item.content === "string") return item.content;
6458
+ return JSON.stringify(item, null, 2);
6459
+ }).join("\n\n---\n\n");
6460
+ }
6461
+ if (content && typeof content === "object") {
6462
+ if (typeof content.text === "string") return content.text;
6463
+ return JSON.stringify(content, null, 2);
6464
+ }
6465
+ return String(content);
6466
+ };
6467
+ logger.logLLMPrompt("classifyQuestionCategory", "system", extractTextContent(prompts.system));
6468
+ logger.logLLMPrompt("classifyQuestionCategory", "user", extractTextContent(prompts.user));
6298
6469
  const result = await LLM.stream(
6299
6470
  {
6300
6471
  sys: prompts.system,
@@ -6319,6 +6490,8 @@ ${executedToolsText}`);
6319
6490
  confidence: result.confidence
6320
6491
  }
6321
6492
  );
6493
+ const methodDuration = Date.now() - methodStartTime;
6494
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | category: ${result.category} | confidence: ${result.confidence}% | tools: ${(result.externalTools || []).length}`);
6322
6495
  return {
6323
6496
  category: result.category || "data_analysis",
6324
6497
  externalTools: result.externalTools || [],
@@ -6327,8 +6500,9 @@ ${executedToolsText}`);
6327
6500
  confidence: result.confidence || 0
6328
6501
  };
6329
6502
  } catch (error) {
6503
+ const methodDuration = Date.now() - methodStartTime;
6330
6504
  const errorMsg = error instanceof Error ? error.message : String(error);
6331
- logger.error(`[${this.getProviderName()}] Error classifying question category: ${errorMsg}`);
6505
+ logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
6332
6506
  logger.debug(`[${this.getProviderName()}] Category classification error details:`, error);
6333
6507
  throw error;
6334
6508
  }
@@ -6339,9 +6513,15 @@ ${executedToolsText}`);
6339
6513
  * Also adapts the cached text response to match the new question
6340
6514
  */
6341
6515
  async adaptUIBlockParameters(currentUserPrompt, originalUserPrompt, matchedUIBlock, apiKey, logCollector, cachedTextResponse) {
6516
+ const methodStartTime = Date.now();
6517
+ const methodName = "adaptUIBlockParameters";
6518
+ const promptPreview = currentUserPrompt.substring(0, 50) + (currentUserPrompt.length > 50 ? "..." : "");
6519
+ logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("complex")} | prompt: "${promptPreview}"`);
6342
6520
  try {
6343
6521
  const component = matchedUIBlock?.generatedComponentMetadata || matchedUIBlock?.component;
6344
6522
  if (!matchedUIBlock || !component) {
6523
+ const methodDuration2 = Date.now() - methodStartTime;
6524
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration2}ms | result: no component found`);
6345
6525
  return {
6346
6526
  success: false,
6347
6527
  explanation: "No component found in matched UI block"
@@ -6374,9 +6554,8 @@ ${executedToolsText}`);
6374
6554
  // Parse as JSON
6375
6555
  );
6376
6556
  if (!result.success) {
6377
- logger.info(
6378
- `[${this.getProviderName()}] Could not adapt UI block: ${result.reason}`
6379
- );
6557
+ const methodDuration2 = Date.now() - methodStartTime;
6558
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration2}ms | result: adaptation failed - ${result.reason}`);
6380
6559
  logCollector?.warn(
6381
6560
  "Could not adapt matched UI block",
6382
6561
  "explanation",
@@ -6401,6 +6580,8 @@ ${executedToolsText}`);
6401
6580
  componentType: result.adaptedComponent?.type
6402
6581
  }
6403
6582
  );
6583
+ const methodDuration = Date.now() - methodStartTime;
6584
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | result: success | changes: ${(result.parametersChanged || []).length}`);
6404
6585
  return {
6405
6586
  success: true,
6406
6587
  adaptedComponent: result.adaptedComponent,
@@ -6409,8 +6590,9 @@ ${executedToolsText}`);
6409
6590
  explanation: result.explanation || "Parameters adapted successfully"
6410
6591
  };
6411
6592
  } catch (error) {
6593
+ const methodDuration = Date.now() - methodStartTime;
6412
6594
  const errorMsg = error instanceof Error ? error.message : String(error);
6413
- logger.error(`[${this.getProviderName()}] Error adapting UI block parameters: ${errorMsg}`);
6595
+ logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
6414
6596
  logger.debug(`[${this.getProviderName()}] Adaptation error details:`, error);
6415
6597
  return {
6416
6598
  success: false,
@@ -6431,6 +6613,10 @@ ${executedToolsText}`);
6431
6613
  * @param userId - Optional user ID for fetching user-specific knowledge base nodes
6432
6614
  */
6433
6615
  async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory, streamCallback, collections, components, externalTools, category, userId) {
6616
+ const methodStartTime = Date.now();
6617
+ const methodName = "generateTextResponse";
6618
+ const promptPreview = userPrompt.substring(0, 50) + (userPrompt.length > 50 ? "..." : "");
6619
+ logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("complex")} | category: ${category} | prompt: "${promptPreview}"`);
6434
6620
  const errors = [];
6435
6621
  logger.debug(`[${this.getProviderName()}] Starting text response generation`);
6436
6622
  logger.debug(`[${this.getProviderName()}] User prompt: "${userPrompt.substring(0, 50)}..."`);
@@ -6495,10 +6681,24 @@ ${executedToolsText}`);
6495
6681
  AVAILABLE_EXTERNAL_TOOLS: availableToolsDoc,
6496
6682
  CURRENT_DATETIME: getCurrentDateTimeForPrompt()
6497
6683
  });
6498
- const sysPrompt = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
6499
- const usrPrompt = Array.isArray(prompts.user) ? prompts.user.join("\n") : prompts.user;
6500
- logger.logLLMPrompt("generateTextResponse", "system", sysPrompt);
6501
- logger.logLLMPrompt("generateTextResponse", "user", usrPrompt);
6684
+ const extractText = (content) => {
6685
+ if (typeof content === "string") return content;
6686
+ if (Array.isArray(content)) {
6687
+ return content.map((item) => {
6688
+ if (typeof item === "string") return item;
6689
+ if (item && typeof item.text === "string") return item.text;
6690
+ if (item && item.content && typeof item.content === "string") return item.content;
6691
+ return JSON.stringify(item, null, 2);
6692
+ }).join("\n\n---\n\n");
6693
+ }
6694
+ if (content && typeof content === "object") {
6695
+ if (typeof content.text === "string") return content.text;
6696
+ return JSON.stringify(content, null, 2);
6697
+ }
6698
+ return String(content);
6699
+ };
6700
+ logger.logLLMPrompt("generateTextResponse", "system", extractText(prompts.system));
6701
+ logger.logLLMPrompt("generateTextResponse", "user", extractText(prompts.user));
6502
6702
  logger.debug(`[${this.getProviderName()}] Loaded text-response prompts with schema`);
6503
6703
  logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
6504
6704
  logCollector?.info("Generating text response with query execution capability...");
@@ -6944,7 +7144,8 @@ ${errorMsg}
6944
7144
  logger.info(`[${this.getProviderName()}] Text response stream completed`);
6945
7145
  const textResponse = fullStreamedText || result || "I apologize, but I was unable to generate a response.";
6946
7146
  if (maxAttemptsReached) {
6947
- logger.warn(`[${this.getProviderName()}] Max query attempts reached, returning failure response`);
7147
+ const methodDuration2 = Date.now() - methodStartTime;
7148
+ logger.warn(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration2}ms | result: max attempts reached`);
6948
7149
  logCollector?.error("Failed to generate valid query after maximum attempts");
6949
7150
  return {
6950
7151
  success: false,
@@ -7021,7 +7222,10 @@ ${errorMsg}
7021
7222
  logCollector,
7022
7223
  componentStreamCallback,
7023
7224
  deferredTools,
7024
- executedToolsList
7225
+ executedToolsList,
7226
+ collections,
7227
+ userId,
7228
+ userPrompt
7025
7229
  );
7026
7230
  matchedComponents = matchResult.components;
7027
7231
  layoutTitle = matchResult.layoutTitle;
@@ -7047,6 +7251,8 @@ ${errorMsg}
7047
7251
  }
7048
7252
  };
7049
7253
  }
7254
+ const methodDuration = Date.now() - methodStartTime;
7255
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | result: success | components: ${matchedComponents.length} | actions: ${actions.length}`);
7050
7256
  return {
7051
7257
  success: true,
7052
7258
  data: {
@@ -7058,8 +7264,9 @@ ${errorMsg}
7058
7264
  errors: []
7059
7265
  };
7060
7266
  } catch (error) {
7267
+ const methodDuration = Date.now() - methodStartTime;
7061
7268
  const errorMsg = error instanceof Error ? error.message : String(error);
7062
- logger.error(`[${this.getProviderName()}] Error generating text response: ${errorMsg}`);
7269
+ logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
7063
7270
  logCollector?.error(`Error generating text response: ${errorMsg}`);
7064
7271
  userPromptErrorLogger.logLlmError(
7065
7272
  this.getProviderName(),
@@ -7101,7 +7308,6 @@ ${errorMsg}
7101
7308
  logger.logLLMPrompt("handleUserRequest", "user", `User Prompt: ${userPrompt}`);
7102
7309
  try {
7103
7310
  logger.info(`[${this.getProviderName()}] Step 1: Searching previous conversations...`);
7104
- logCollector?.info("Step 1: Searching for similar previous conversations...");
7105
7311
  const conversationMatch = await conversation_search_default.searchConversationsWithReranking({
7106
7312
  userPrompt,
7107
7313
  collections,
@@ -7313,6 +7519,10 @@ ${errorMsg}
7313
7519
  * For general/conversational questions without components, pass textResponse instead
7314
7520
  */
7315
7521
  async generateNextQuestions(originalUserPrompt, component, componentData, apiKey, logCollector, conversationHistory, textResponse) {
7522
+ const methodStartTime = Date.now();
7523
+ const methodName = "generateNextQuestions";
7524
+ const promptPreview = originalUserPrompt.substring(0, 50) + (originalUserPrompt.length > 50 ? "..." : "");
7525
+ logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("simple")} | prompt: "${promptPreview}"`);
7316
7526
  try {
7317
7527
  let component_info;
7318
7528
  if (component) {
@@ -7361,10 +7571,13 @@ ${errorMsg}
7361
7571
  questions: nextQuestions
7362
7572
  }
7363
7573
  );
7574
+ const methodDuration = Date.now() - methodStartTime;
7575
+ logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | questions: ${nextQuestions.length}`);
7364
7576
  return nextQuestions;
7365
7577
  } catch (error) {
7578
+ const methodDuration = Date.now() - methodStartTime;
7366
7579
  const errorMsg = error instanceof Error ? error.message : String(error);
7367
- logger.error(`[${this.getProviderName()}] Error generating next questions: ${errorMsg}`);
7580
+ logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
7368
7581
  logger.debug(`[${this.getProviderName()}] Next questions generation error details:`, error);
7369
7582
  logCollector?.error(`Error generating next questions: ${errorMsg}`);
7370
7583
  return [];
@@ -10372,6 +10585,8 @@ async function handleArtifactsRequest(data, collections, sendMessage) {
10372
10585
  const status = requestData?.status;
10373
10586
  const deleted = requestData?.deleted;
10374
10587
  const limit = requestData?.limit;
10588
+ const filters = requestData?.filters;
10589
+ const sort = requestData?.sort;
10375
10590
  switch (operation) {
10376
10591
  case "create":
10377
10592
  await handleCreate6(id, name, createdBy, dsl, status, executeCollection, sendMessage, from.id);
@@ -10388,6 +10603,9 @@ async function handleArtifactsRequest(data, collections, sendMessage) {
10388
10603
  case "getOne":
10389
10604
  await handleGetOne6(id, artifactId, executeCollection, sendMessage, from.id);
10390
10605
  break;
10606
+ case "query":
10607
+ await handleQuery6(id, { filters, limit, sort }, executeCollection, sendMessage, from.id);
10608
+ break;
10391
10609
  default:
10392
10610
  sendResponse8(id, {
10393
10611
  success: false,
@@ -10511,6 +10729,27 @@ async function handleGetOne6(id, artifactId, executeCollection, sendMessage, cli
10511
10729
  }, sendMessage, clientId);
10512
10730
  }
10513
10731
  }
10732
+ async function handleQuery6(id, queryParams, executeCollection, sendMessage, clientId) {
10733
+ try {
10734
+ const result = await executeCollection("artifacts", "query", {
10735
+ filters: queryParams.filters,
10736
+ limit: queryParams.limit || 50,
10737
+ sort: queryParams.sort || "DESC"
10738
+ });
10739
+ sendResponse8(id, {
10740
+ success: true,
10741
+ data: result.data,
10742
+ count: result.count,
10743
+ message: `Query returned ${result.count} artifacts`
10744
+ }, sendMessage, clientId);
10745
+ logger.info(`Query artifacts (count: ${result.count})`);
10746
+ } catch (error) {
10747
+ sendResponse8(id, {
10748
+ success: false,
10749
+ error: error instanceof Error ? error.message : "Failed to query artifacts"
10750
+ }, sendMessage, clientId);
10751
+ }
10752
+ }
10514
10753
  function sendResponse8(id, res, sendMessage, clientId) {
10515
10754
  const response = {
10516
10755
  id: id || "unknown",
@@ -11037,7 +11276,7 @@ async function handleMenusRequest(data, collections, sendMessage) {
11037
11276
  await handleGetHierarchy(id, executeCollection, sendMessage, from.id);
11038
11277
  break;
11039
11278
  case "query":
11040
- await handleQuery6(id, filters, limit, sort, executeCollection, sendMessage, from.id);
11279
+ await handleQuery7(id, filters, limit, sort, executeCollection, sendMessage, from.id);
11041
11280
  break;
11042
11281
  case "reorder":
11043
11282
  await handleReorder(id, items, executeCollection, sendMessage, from.id);
@@ -11249,7 +11488,7 @@ async function handleGetHierarchy(id, executeCollection, sendMessage, clientId)
11249
11488
  }, sendMessage, clientId);
11250
11489
  }
11251
11490
  }
11252
- async function handleQuery6(id, filters, limit, sort, executeCollection, sendMessage, clientId) {
11491
+ async function handleQuery7(id, filters, limit, sort, executeCollection, sendMessage, clientId) {
11253
11492
  try {
11254
11493
  const result = await executeCollection("menus", "query", {
11255
11494
  filters: filters || {},