@superatomai/sdk-node 0.0.58 → 0.0.60

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,122 @@ 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 subqueryOrderByPattern = /\(\s*SELECT\s+(?!TOP\s)([^()]*?)\s+ORDER\s+BY\s+[^()]+\)/gi;
1889
+ let subqueryMatch;
1890
+ let subqueryFixed = false;
1891
+ while ((subqueryMatch = subqueryOrderByPattern.exec(fixedQuery)) !== null) {
1892
+ const fullMatch = subqueryMatch[0];
1893
+ if (!/\bTOP\s+\d+/i.test(fullMatch) && !/\bOFFSET\b/i.test(fullMatch)) {
1894
+ const fixedSubquery = fullMatch.replace(
1895
+ /\(\s*SELECT\s+/i,
1896
+ "(SELECT TOP 100 "
1897
+ );
1898
+ fixedQuery = fixedQuery.replace(fullMatch, fixedSubquery);
1899
+ subqueryFixed = true;
1900
+ }
1901
+ }
1902
+ if (subqueryFixed) {
1903
+ fixes.push("Added TOP to subquery with ORDER BY (MSSQL requirement)");
1904
+ }
1905
+ const originalLength = fixedQuery.length;
1906
+ fixedQuery = fixedQuery.replace(/\s+/g, " ").trim();
1907
+ if (fixedQuery.length !== originalLength) {
1908
+ }
1909
+ return {
1910
+ query: fixedQuery,
1911
+ fixed: fixes.length > 0,
1912
+ fixes
1913
+ };
1914
+ }
1798
1915
  var init_utils = __esm({
1799
1916
  "src/userResponse/utils.ts"() {
1800
1917
  "use strict";
@@ -5905,7 +6022,7 @@ var BaseLLM = class {
5905
6022
  * @param componentStreamCallback - Optional callback to stream primary KPI component as soon as it's identified
5906
6023
  * @returns Object containing matched components, layout title/description, and follow-up actions
5907
6024
  */
5908
- async matchComponentsFromAnalysis(analysisContent, components, apiKey, logCollector, componentStreamCallback, deferredTools, executedTools) {
6025
+ async matchComponentsFromAnalysis(analysisContent, components, apiKey, logCollector, componentStreamCallback, deferredTools, executedTools, collections, userId, userPrompt) {
5909
6026
  const methodStartTime = Date.now();
5910
6027
  const methodName = "matchComponentsFromAnalysis";
5911
6028
  logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("complex")}`);
@@ -5968,6 +6085,16 @@ ${fieldsText}`;
5968
6085
  }
5969
6086
  const schemaDoc = schema.generateSchemaDocumentation();
5970
6087
  const databaseRules = await promptLoader.loadDatabaseRules();
6088
+ let knowledgeBaseContext = "No additional knowledge base context available.";
6089
+ if (collections) {
6090
+ const kbResult = await knowledge_base_default.getAllKnowledgeBase({
6091
+ prompt: userPrompt || analysisContent,
6092
+ collections,
6093
+ userId,
6094
+ topK: 3
6095
+ });
6096
+ knowledgeBaseContext = kbResult.combinedContext || knowledgeBaseContext;
6097
+ }
5971
6098
  const prompts = await promptLoader.loadPrompts("match-text-components", {
5972
6099
  ANALYSIS_CONTENT: analysisContent,
5973
6100
  AVAILABLE_COMPONENTS: availableComponentsText,
@@ -5975,11 +6102,27 @@ ${fieldsText}`;
5975
6102
  DATABASE_RULES: databaseRules,
5976
6103
  DEFERRED_TOOLS: deferredToolsText,
5977
6104
  EXECUTED_TOOLS: executedToolsText,
6105
+ KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext,
5978
6106
  CURRENT_DATETIME: getCurrentDateTimeForPrompt()
5979
6107
  });
5980
6108
  logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
5981
- const systemPromptStr = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
5982
- logger.logLLMPrompt("matchComponentsFromAnalysis", "system", systemPromptStr);
6109
+ const extractPromptText = (content) => {
6110
+ if (typeof content === "string") return content;
6111
+ if (Array.isArray(content)) {
6112
+ return content.map((item) => {
6113
+ if (typeof item === "string") return item;
6114
+ if (item && typeof item.text === "string") return item.text;
6115
+ if (item && item.content && typeof item.content === "string") return item.content;
6116
+ return JSON.stringify(item, null, 2);
6117
+ }).join("\n\n---\n\n");
6118
+ }
6119
+ if (content && typeof content === "object") {
6120
+ if (typeof content.text === "string") return content.text;
6121
+ return JSON.stringify(content, null, 2);
6122
+ }
6123
+ return String(content);
6124
+ };
6125
+ logger.logLLMPrompt("matchComponentsFromAnalysis", "system", extractPromptText(prompts.system));
5983
6126
  logger.logLLMPrompt("matchComponentsFromAnalysis", "user", `Text Analysis:
5984
6127
  ${analysisContent}
5985
6128
 
@@ -6204,6 +6347,18 @@ ${executedToolsText}`);
6204
6347
  cleanedProps.query = null;
6205
6348
  }
6206
6349
  }
6350
+ if (cleanedProps.query) {
6351
+ const queryStr = typeof cleanedProps.query === "string" ? cleanedProps.query : cleanedProps.query?.sql || "";
6352
+ const { query: fixedQuery, fixed, fixes } = validateAndFixSqlQuery(queryStr);
6353
+ if (fixed) {
6354
+ logger.warn(`[${this.getProviderName()}] SQL fixes applied to component query: ${fixes.join("; ")}`);
6355
+ if (typeof cleanedProps.query === "string") {
6356
+ cleanedProps.query = fixedQuery;
6357
+ } else if (cleanedProps.query?.sql) {
6358
+ cleanedProps.query.sql = fixedQuery;
6359
+ }
6360
+ }
6361
+ }
6207
6362
  if (cleanedProps.query && cleanedProps.externalTool) {
6208
6363
  logger.info(`[${this.getProviderName()}] Both query and externalTool exist, keeping both - frontend will decide`);
6209
6364
  }
@@ -6260,10 +6415,24 @@ ${executedToolsText}`);
6260
6415
  SCHEMA_DOC: schemaDoc || "No database schema available",
6261
6416
  CURRENT_DATETIME: getCurrentDateTimeForPrompt()
6262
6417
  });
6263
- const systemPrompt = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
6264
- const userPromptText = Array.isArray(prompts.user) ? prompts.user.join("\n") : prompts.user;
6265
- logger.logLLMPrompt("classifyQuestionCategory", "system", systemPrompt);
6266
- logger.logLLMPrompt("classifyQuestionCategory", "user", userPromptText);
6418
+ const extractTextContent = (content) => {
6419
+ if (typeof content === "string") return content;
6420
+ if (Array.isArray(content)) {
6421
+ return content.map((item) => {
6422
+ if (typeof item === "string") return item;
6423
+ if (item && typeof item.text === "string") return item.text;
6424
+ if (item && item.content && typeof item.content === "string") return item.content;
6425
+ return JSON.stringify(item, null, 2);
6426
+ }).join("\n\n---\n\n");
6427
+ }
6428
+ if (content && typeof content === "object") {
6429
+ if (typeof content.text === "string") return content.text;
6430
+ return JSON.stringify(content, null, 2);
6431
+ }
6432
+ return String(content);
6433
+ };
6434
+ logger.logLLMPrompt("classifyQuestionCategory", "system", extractTextContent(prompts.system));
6435
+ logger.logLLMPrompt("classifyQuestionCategory", "user", extractTextContent(prompts.user));
6267
6436
  const result = await LLM.stream(
6268
6437
  {
6269
6438
  sys: prompts.system,
@@ -6479,10 +6648,24 @@ ${executedToolsText}`);
6479
6648
  AVAILABLE_EXTERNAL_TOOLS: availableToolsDoc,
6480
6649
  CURRENT_DATETIME: getCurrentDateTimeForPrompt()
6481
6650
  });
6482
- const sysPrompt = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
6483
- const usrPrompt = Array.isArray(prompts.user) ? prompts.user.join("\n") : prompts.user;
6484
- logger.logLLMPrompt("generateTextResponse", "system", sysPrompt);
6485
- logger.logLLMPrompt("generateTextResponse", "user", usrPrompt);
6651
+ const extractText = (content) => {
6652
+ if (typeof content === "string") return content;
6653
+ if (Array.isArray(content)) {
6654
+ return content.map((item) => {
6655
+ if (typeof item === "string") return item;
6656
+ if (item && typeof item.text === "string") return item.text;
6657
+ if (item && item.content && typeof item.content === "string") return item.content;
6658
+ return JSON.stringify(item, null, 2);
6659
+ }).join("\n\n---\n\n");
6660
+ }
6661
+ if (content && typeof content === "object") {
6662
+ if (typeof content.text === "string") return content.text;
6663
+ return JSON.stringify(content, null, 2);
6664
+ }
6665
+ return String(content);
6666
+ };
6667
+ logger.logLLMPrompt("generateTextResponse", "system", extractText(prompts.system));
6668
+ logger.logLLMPrompt("generateTextResponse", "user", extractText(prompts.user));
6486
6669
  logger.debug(`[${this.getProviderName()}] Loaded text-response prompts with schema`);
6487
6670
  logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
6488
6671
  logCollector?.info("Generating text response with query execution capability...");
@@ -6515,7 +6698,13 @@ ${executedToolsText}`);
6515
6698
  (t) => t.executionType === "immediate" || t.executionType === "deferred" && t.userProvidedData
6516
6699
  );
6517
6700
  logger.info(`[${this.getProviderName()}] Executable tools: ${executableTools.length} of ${externalTools.length} total`);
6701
+ const addedToolIds = /* @__PURE__ */ new Set();
6518
6702
  executableTools.forEach((tool) => {
6703
+ if (addedToolIds.has(tool.id)) {
6704
+ logger.info(`[${this.getProviderName()}] Skipping duplicate tool definition: ${tool.id} (already added)`);
6705
+ return;
6706
+ }
6707
+ addedToolIds.add(tool.id);
6519
6708
  logger.info(`[${this.getProviderName()}] Processing executable tool:`, JSON.stringify(tool, null, 2));
6520
6709
  const properties = {};
6521
6710
  const required = [];
@@ -6585,7 +6774,7 @@ ${executedToolsText}`);
6585
6774
  input_schema: inputSchema
6586
6775
  });
6587
6776
  });
6588
- logger.info(`[${this.getProviderName()}] Added ${executableTools.length} executable tools to tool calling capability (${externalTools.length - executableTools.length} deferred tools await form input)`);
6777
+ logger.info(`[${this.getProviderName()}] Added ${addedToolIds.size} unique tool definitions from ${executableTools.length} tool calls (${externalTools.length - executableTools.length} deferred tools await form input)`);
6589
6778
  logger.info(`[${this.getProviderName()}] Complete tools array:`, JSON.stringify(tools, null, 2));
6590
6779
  }
6591
6780
  const queryAttempts = /* @__PURE__ */ new Map();
@@ -7006,7 +7195,10 @@ ${errorMsg}
7006
7195
  logCollector,
7007
7196
  componentStreamCallback,
7008
7197
  deferredTools,
7009
- executedToolsList
7198
+ executedToolsList,
7199
+ collections,
7200
+ userId,
7201
+ userPrompt
7010
7202
  );
7011
7203
  matchedComponents = matchResult.components;
7012
7204
  layoutTitle = matchResult.layoutTitle;
@@ -7089,7 +7281,6 @@ ${errorMsg}
7089
7281
  logger.logLLMPrompt("handleUserRequest", "user", `User Prompt: ${userPrompt}`);
7090
7282
  try {
7091
7283
  logger.info(`[${this.getProviderName()}] Step 1: Searching previous conversations...`);
7092
- logCollector?.info("Step 1: Searching for similar previous conversations...");
7093
7284
  const conversationMatch = await conversation_search_default.searchConversationsWithReranking({
7094
7285
  userPrompt,
7095
7286
  collections,