@superatomai/sdk-node 0.0.4 → 0.0.5

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.js CHANGED
@@ -441,7 +441,8 @@ __export(index_exports, {
441
441
  ThreadManager: () => ThreadManager,
442
442
  UIBlock: () => UIBlock,
443
443
  UILogCollector: () => UILogCollector,
444
- UserManager: () => UserManager
444
+ UserManager: () => UserManager,
445
+ logger: () => logger
445
446
  });
446
447
  module.exports = __toCommonJS(index_exports);
447
448
 
@@ -641,6 +642,18 @@ var DSLRendererPropsSchema2 = import_zod2.z.object({
641
642
  });
642
643
 
643
644
  // src/types.ts
645
+ var UserSchema = import_zod3.z.object({
646
+ username: import_zod3.z.string().min(1, "Username is required"),
647
+ email: import_zod3.z.string().email("Invalid email format").optional(),
648
+ password: import_zod3.z.string().min(1, "Password is required"),
649
+ fullname: import_zod3.z.string().optional(),
650
+ role: import_zod3.z.string().optional(),
651
+ wsIds: import_zod3.z.array(import_zod3.z.string()).optional()
652
+ // Only in memory, not persisted to file
653
+ });
654
+ var UsersDataSchema = import_zod3.z.object({
655
+ users: import_zod3.z.array(UserSchema)
656
+ });
644
657
  var MessageParticipantSchema = import_zod3.z.object({
645
658
  id: import_zod3.z.string().optional(),
646
659
  type: import_zod3.z.string().optional()
@@ -741,7 +754,10 @@ var UsersRequestPayloadSchema = import_zod3.z.object({
741
754
  operation: import_zod3.z.enum(["create", "update", "delete", "getAll", "getOne"]),
742
755
  data: import_zod3.z.object({
743
756
  username: import_zod3.z.string().optional(),
744
- password: import_zod3.z.string().optional()
757
+ email: import_zod3.z.string().email("Invalid email format").optional(),
758
+ password: import_zod3.z.string().optional(),
759
+ fullname: import_zod3.z.string().optional(),
760
+ role: import_zod3.z.string().optional()
745
761
  }).optional()
746
762
  });
747
763
  var UsersRequestMessageSchema = import_zod3.z.object({
@@ -807,20 +823,91 @@ var ReportsRequestMessageSchema = import_zod3.z.object({
807
823
 
808
824
  // src/utils/logger.ts
809
825
  var PREFIX = "[SuperatomSDK]";
810
- var logger = {
811
- info: (...args) => {
812
- console.log(PREFIX, ...args);
813
- },
814
- error: (...args) => {
815
- console.error(PREFIX, ...args);
816
- },
817
- warn: (...args) => {
818
- console.warn(PREFIX, ...args);
819
- },
820
- debug: (...args) => {
821
- console.log(PREFIX, "[DEBUG]", ...args);
826
+ var LOG_LEVEL_PRIORITY = {
827
+ errors: 0,
828
+ warnings: 1,
829
+ info: 2,
830
+ verbose: 3
831
+ };
832
+ var MESSAGE_LEVEL_PRIORITY = {
833
+ error: 0,
834
+ warn: 1,
835
+ info: 2,
836
+ debug: 3
837
+ };
838
+ var Logger = class {
839
+ constructor() {
840
+ const envLevel = (process.env.SUPERATOM_LOG_LEVEL || "info").toLowerCase();
841
+ if (this.isValidLogLevel(envLevel)) {
842
+ this.currentLevel = envLevel;
843
+ } else {
844
+ this.currentLevel = "info";
845
+ console.warn(
846
+ `${PREFIX} Invalid log level "${envLevel}". Using default "info". Valid levels: errors, warnings, info, verbose`
847
+ );
848
+ }
849
+ this.currentLevelPriority = LOG_LEVEL_PRIORITY[this.currentLevel];
850
+ }
851
+ /**
852
+ * Check if a string is a valid log level
853
+ */
854
+ isValidLogLevel(level) {
855
+ return level === "errors" || level === "warnings" || level === "info" || level === "verbose";
856
+ }
857
+ /**
858
+ * Check if a message should be logged based on current log level
859
+ */
860
+ shouldLog(messageLevel) {
861
+ const messagePriority = MESSAGE_LEVEL_PRIORITY[messageLevel];
862
+ return messagePriority <= this.currentLevelPriority;
863
+ }
864
+ /**
865
+ * Get current log level
866
+ */
867
+ getLogLevel() {
868
+ return this.currentLevel;
869
+ }
870
+ /**
871
+ * Set log level programmatically
872
+ */
873
+ setLogLevel(level) {
874
+ this.currentLevel = level;
875
+ this.currentLevelPriority = LOG_LEVEL_PRIORITY[level];
876
+ }
877
+ /**
878
+ * Log info message (shown for info and verbose levels)
879
+ */
880
+ info(...args) {
881
+ if (this.shouldLog("info")) {
882
+ console.log(PREFIX, ...args);
883
+ }
884
+ }
885
+ /**
886
+ * Log error message (shown for all levels)
887
+ */
888
+ error(...args) {
889
+ if (this.shouldLog("error")) {
890
+ console.error(PREFIX, ...args);
891
+ }
892
+ }
893
+ /**
894
+ * Log warning message (shown for warnings, info, and verbose levels)
895
+ */
896
+ warn(...args) {
897
+ if (this.shouldLog("warn")) {
898
+ console.warn(PREFIX, ...args);
899
+ }
900
+ }
901
+ /**
902
+ * Log debug message (only shown for verbose level)
903
+ */
904
+ debug(...args) {
905
+ if (this.shouldLog("debug")) {
906
+ console.log(PREFIX, "[DEBUG]", ...args);
907
+ }
822
908
  }
823
909
  };
910
+ var logger = new Logger();
824
911
 
825
912
  // src/threads/uiblock.ts
826
913
  var import_crypto = require("crypto");
@@ -855,13 +942,15 @@ var UIBlock = class {
855
942
  * @param generatedComponentMetadata - Optional metadata about the generated component
856
943
  * @param actions - Optional array of available actions
857
944
  * @param id - Optional custom ID, generates UUID if not provided
945
+ * @param textResponse - Optional text response from LLM
858
946
  */
859
- constructor(userQuestion, componentData = {}, generatedComponentMetadata = {}, actions = [], id) {
947
+ constructor(userQuestion, componentData = {}, generatedComponentMetadata = {}, actions = [], id, textResponse = null) {
860
948
  this.id = id || (0, import_crypto.randomUUID)();
861
949
  this.userQuestion = userQuestion;
862
950
  this.componentData = componentData;
863
951
  this.generatedComponentMetadata = generatedComponentMetadata;
864
952
  this.actions = actions;
953
+ this.textResponse = textResponse;
865
954
  this.createdAt = /* @__PURE__ */ new Date();
866
955
  }
867
956
  /**
@@ -980,6 +1069,18 @@ var UIBlock = class {
980
1069
  const processedData = this.processDataForStorage(data);
981
1070
  this.componentData = { ...this.componentData, ...processedData };
982
1071
  }
1072
+ /**
1073
+ * Get text response
1074
+ */
1075
+ getTextResponse() {
1076
+ return this.textResponse;
1077
+ }
1078
+ /**
1079
+ * Set or update text response
1080
+ */
1081
+ setTextResponse(textResponse) {
1082
+ this.textResponse = textResponse;
1083
+ }
983
1084
  /**
984
1085
  * Get all actions (only if they are resolved, not if fetching)
985
1086
  */
@@ -1063,6 +1164,7 @@ var UIBlock = class {
1063
1164
  userQuestion: this.userQuestion,
1064
1165
  generatedComponentMetadata: this.generatedComponentMetadata,
1065
1166
  componentData: this.componentData,
1167
+ textResponse: this.textResponse,
1066
1168
  actions: actionsValue,
1067
1169
  isFetchingActions: this.actions instanceof Promise,
1068
1170
  createdAt: this.createdAt.toISOString()
@@ -1497,9 +1599,9 @@ function getUserManager() {
1497
1599
  }
1498
1600
  return currentUserManager;
1499
1601
  }
1500
- function findUserByUsername(username) {
1602
+ function findUserByUsernameOrEmail(identifier) {
1501
1603
  const manager = getUserManager();
1502
- const user = manager.getUser(username);
1604
+ const user = manager.getUserByUsernameOrEmail(identifier);
1503
1605
  return user || null;
1504
1606
  }
1505
1607
  function addWsIdToUser(username, wsId) {
@@ -1521,60 +1623,81 @@ async function cleanupUserStorage() {
1521
1623
 
1522
1624
  // src/auth/validator.ts
1523
1625
  function validateUser(credentials) {
1524
- const { username, password } = credentials;
1525
- if (!username || !password) {
1526
- logger.warn("Validation failed: Username and password are required");
1626
+ const { username, email, password } = credentials;
1627
+ const identifier = username || email;
1628
+ logger.debug("[validateUser] Starting user validation");
1629
+ logger.debug(`[validateUser] Username provided: ${username ? "\u2713" : "\u2717"}, Email provided: ${email ? "\u2713" : "\u2717"}, Password provided: ${password ? "\u2713" : "\u2717"}`);
1630
+ if (!identifier || !password) {
1631
+ logger.warn("[validateUser] Validation failed: Username/email and password are required");
1527
1632
  return {
1528
1633
  success: false,
1529
- error: "Username and password are required"
1634
+ error: "Username or email and password are required"
1530
1635
  };
1531
1636
  }
1532
- const user = findUserByUsername(username);
1637
+ logger.debug(`[validateUser] Looking up user by identifier: ${identifier}`);
1638
+ const user = findUserByUsernameOrEmail(identifier);
1533
1639
  if (!user) {
1534
- logger.warn(`Validation failed: User not found - ${username}`);
1640
+ logger.warn(`[validateUser] Validation failed: User not found - ${identifier}`);
1535
1641
  return {
1536
1642
  success: false,
1537
- error: "Invalid username"
1643
+ error: "Invalid username or email"
1538
1644
  };
1539
1645
  }
1646
+ logger.debug(`[validateUser] User found: ${user.username}, verifying password`);
1540
1647
  const hashedPassword = hashPassword(user.password);
1541
1648
  if (hashedPassword !== password) {
1542
- logger.warn(`Validation failed: Invalid password for user - ${username}`);
1649
+ logger.warn(`[validateUser] Validation failed: Invalid password for user - ${user.username}`);
1650
+ logger.debug(`[validateUser] Password hash mismatch for user: ${user.username}`);
1543
1651
  return {
1544
1652
  success: false,
1545
1653
  error: "Invalid password"
1546
1654
  };
1547
1655
  }
1548
- logger.debug(`User validated successfully: ${username}`);
1656
+ logger.info(`[validateUser] \u2713 User validated successfully: ${user.username}`);
1657
+ logger.debug(`[validateUser] Returning user data for: ${user.username}`);
1549
1658
  return {
1550
1659
  success: true,
1551
- data: user.username
1660
+ data: user.username,
1661
+ username: user.username
1552
1662
  };
1553
1663
  }
1554
1664
  function authenticateAndStoreWsId(credentials, wsId) {
1665
+ const identifier = credentials.username || credentials.email;
1666
+ logger.debug("[authenticateAndStoreWsId] Starting authentication and WebSocket ID storage");
1667
+ logger.debug("[authenticateAndStoreWsId] Validating user credentials");
1555
1668
  const validationResult = validateUser(credentials);
1556
1669
  if (!validationResult.success) {
1670
+ logger.warn(`[authenticateAndStoreWsId] User validation failed for: ${identifier}`);
1557
1671
  return validationResult;
1558
1672
  }
1559
- const stored = addWsIdToUser(credentials.username, wsId);
1560
- if (!stored) {
1561
- logger.error(`Failed to store WebSocket ID for user: ${credentials.username}`);
1562
- return {
1563
- success: false,
1564
- error: "Failed to store user session"
1565
- };
1566
- }
1567
- logger.info(`WebSocket ID stored for user: ${credentials.username}`);
1673
+ const username = validationResult.username;
1674
+ logger.info(`[authenticateAndStoreWsId] User ${username} validated, storing WebSocket ID`);
1675
+ logger.debug(`[authenticateAndStoreWsId] Calling addWsIdToUser for ${username}`);
1676
+ addWsIdToUser(username, wsId);
1677
+ logger.debug(`[authenticateAndStoreWsId] WebSocket ID ${wsId} associated with user ${username}`);
1568
1678
  return validationResult;
1569
1679
  }
1570
1680
  function verifyAuthToken(authToken) {
1571
1681
  try {
1682
+ logger.debug("[verifyAuthToken] Starting token verification");
1683
+ logger.debug("[verifyAuthToken] Decoding base64 token");
1572
1684
  const decodedString = Buffer.from(authToken, "base64").toString("utf-8");
1685
+ logger.debug("[verifyAuthToken] Parsing decoded token as JSON");
1573
1686
  const credentials = JSON.parse(decodedString);
1574
- logger.debug("Token decoded and parsed successfully");
1575
- return validateUser(credentials);
1687
+ logger.debug("[verifyAuthToken] Token decoded and parsed successfully");
1688
+ logger.debug(`[verifyAuthToken] Token contains username: ${credentials.username ? "\u2713" : "\u2717"}`);
1689
+ logger.debug("[verifyAuthToken] Validating credentials from token");
1690
+ const result = validateUser(credentials);
1691
+ if (result.success) {
1692
+ logger.info(`[verifyAuthToken] \u2713 Token verified successfully for user: ${credentials.username || "unknown"}`);
1693
+ } else {
1694
+ logger.warn(`[verifyAuthToken] Token verification failed: ${result.error}`);
1695
+ }
1696
+ return result;
1576
1697
  } catch (error) {
1577
- logger.error("Failed to verify auth token:", error);
1698
+ const errorMsg = error instanceof Error ? error.message : String(error);
1699
+ logger.error(`[verifyAuthToken] Failed to verify auth token: ${errorMsg}`);
1700
+ logger.debug("[verifyAuthToken] Token verification error details:", error);
1578
1701
  return {
1579
1702
  success: false,
1580
1703
  error: "Invalid token format"
@@ -1585,36 +1708,49 @@ function verifyAuthToken(authToken) {
1585
1708
  // src/handlers/auth-login-requests.ts
1586
1709
  async function handleAuthLoginRequest(data, sendMessage) {
1587
1710
  try {
1711
+ logger.debug("[AUTH_LOGIN_REQ] Parsing incoming auth login request");
1588
1712
  const authRequest = AuthLoginRequestMessageSchema.parse(data);
1589
1713
  const { id, payload } = authRequest;
1590
1714
  const login_data = payload.login_data;
1591
1715
  const wsId = authRequest.from.id;
1716
+ logger.info(`[AUTH_LOGIN_REQ ${id}] Processing auth login request from client: ${wsId}`);
1717
+ logger.debug(`[AUTH_LOGIN_REQ ${id}] Login data present: ${!!login_data}`);
1592
1718
  if (!login_data) {
1719
+ logger.error(`[AUTH_LOGIN_REQ ${id}] Login data not found in request`);
1593
1720
  sendDataResponse2(id, {
1594
1721
  success: false,
1595
1722
  error: "Login data not found"
1596
1723
  }, sendMessage, wsId);
1597
1724
  return;
1598
1725
  }
1726
+ logger.debug(`[AUTH_LOGIN_REQ ${id}] Decoding base64 login data`);
1599
1727
  let loginData;
1600
1728
  try {
1601
1729
  loginData = decodeBase64ToJson(login_data);
1730
+ logger.debug(`[AUTH_LOGIN_REQ ${id}] Login data decoded successfully`);
1602
1731
  } catch (error) {
1732
+ const errorMsg = error instanceof Error ? error.message : String(error);
1733
+ logger.error(`[AUTH_LOGIN_REQ ${id}] Failed to decode login data: ${errorMsg}`);
1734
+ logger.debug(`[AUTH_LOGIN_REQ ${id}] Decode error details:`, error);
1603
1735
  sendDataResponse2(id, {
1604
1736
  success: false,
1605
1737
  error: "Invalid login data format"
1606
1738
  }, sendMessage, wsId);
1607
1739
  return;
1608
1740
  }
1609
- const { username, password } = loginData;
1610
- if (!username) {
1741
+ const { username, email, password } = loginData;
1742
+ const identifier = username || email;
1743
+ logger.debug(`[AUTH_LOGIN_REQ ${id}] Validating credentials - username: ${username ? "\u2713" : "\u2717"}, email: ${email ? "\u2713" : "\u2717"}, password: ${password ? "\u2713" : "\u2717"}`);
1744
+ if (!identifier) {
1745
+ logger.error(`[AUTH_LOGIN_REQ ${id}] Username or email not found in login data`);
1611
1746
  sendDataResponse2(id, {
1612
1747
  success: false,
1613
- error: "Username not found in login data"
1748
+ error: "Username or email is required"
1614
1749
  }, sendMessage, wsId);
1615
1750
  return;
1616
1751
  }
1617
1752
  if (!password) {
1753
+ logger.error(`[AUTH_LOGIN_REQ ${id}] Password not found in login data`);
1618
1754
  sendDataResponse2(id, {
1619
1755
  success: false,
1620
1756
  error: "Password not found in login data"
@@ -1622,20 +1758,46 @@ async function handleAuthLoginRequest(data, sendMessage) {
1622
1758
  return;
1623
1759
  }
1624
1760
  if (!wsId) {
1761
+ logger.error(`[AUTH_LOGIN_REQ ${id}] WebSocket ID not found in request`);
1625
1762
  sendDataResponse2(id, {
1626
1763
  success: false,
1627
1764
  error: "WebSocket ID not found"
1628
1765
  }, sendMessage, wsId);
1629
1766
  return;
1630
1767
  }
1768
+ logger.info(`[AUTH_LOGIN_REQ ${id}] Credentials validated, authenticating user: ${identifier}`);
1769
+ logger.debug(`[AUTH_LOGIN_REQ ${id}] WebSocket ID: ${wsId}`);
1770
+ logger.debug(`[AUTH_LOGIN_REQ ${id}] Calling authenticateAndStoreWsId for user: ${identifier}`);
1631
1771
  const authResult = authenticateAndStoreWsId(
1632
- { username, password },
1772
+ { username, email, password },
1633
1773
  wsId
1634
1774
  );
1775
+ logger.info(`[AUTH_LOGIN_REQ ${id}] Authentication result for ${identifier}: ${authResult.success ? "success" : "failed"}`);
1776
+ if (!authResult.success) {
1777
+ logger.warn(`[AUTH_LOGIN_REQ ${id}] Authentication failed for ${identifier}: ${authResult.error}`);
1778
+ } else {
1779
+ logger.info(`[AUTH_LOGIN_REQ ${id}] User ${authResult.username || identifier} authenticated successfully`);
1780
+ }
1781
+ logger.debug(`[AUTH_LOGIN_REQ ${id}] Sending auth response to client`);
1635
1782
  sendDataResponse2(id, authResult, sendMessage, wsId);
1783
+ logger.info(`[AUTH_LOGIN_REQ ${id}] ${authResult.success ? "\u2713" : "\u2717"} Auth login request completed`);
1636
1784
  return;
1637
1785
  } catch (error) {
1638
- logger.error("Failed to handle auth login request:", error);
1786
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
1787
+ const errorStack = error instanceof Error ? error.stack : void 0;
1788
+ logger.error(`[AUTH_LOGIN_REQ] Failed to handle auth login request: ${errorMessage}`);
1789
+ logger.debug(`[AUTH_LOGIN_REQ] Error stack trace:`, errorStack);
1790
+ try {
1791
+ const parsedData = data;
1792
+ if (parsedData?.id) {
1793
+ sendDataResponse2(parsedData.id, {
1794
+ success: false,
1795
+ error: `Internal error: ${errorMessage}`
1796
+ }, sendMessage, parsedData.from?.id);
1797
+ }
1798
+ } catch (sendError) {
1799
+ logger.error("[AUTH_LOGIN_REQ] Failed to send error response:", sendError);
1800
+ }
1639
1801
  }
1640
1802
  }
1641
1803
  function sendDataResponse2(id, res, sendMessage, clientId) {
@@ -1651,17 +1813,27 @@ function sendDataResponse2(id, res, sendMessage, clientId) {
1651
1813
  ...res
1652
1814
  }
1653
1815
  };
1816
+ logger.debug(`[AUTH_LOGIN_RES ${id}] Sending ${res.success ? "successful" : "failed"} auth response to client: ${clientId}`);
1817
+ logger.debug(`[AUTH_LOGIN_RES ${id}] Response payload size: ${JSON.stringify(response).length} bytes`);
1818
+ if (res.error) {
1819
+ logger.debug(`[AUTH_LOGIN_RES ${id}] Error message: ${res.error}`);
1820
+ }
1654
1821
  sendMessage(response);
1655
1822
  }
1656
1823
 
1657
1824
  // src/handlers/auth-verify-request.ts
1658
1825
  async function handleAuthVerifyRequest(data, sendMessage) {
1659
1826
  try {
1827
+ logger.debug("[AUTH_VERIFY_REQ] Parsing incoming auth verify request");
1660
1828
  const authRequest = AuthVerifyRequestMessageSchema.parse(data);
1661
1829
  const { id, payload } = authRequest;
1662
1830
  const token = payload.token;
1663
1831
  const wsId = authRequest.from.id;
1832
+ logger.info(`[AUTH_VERIFY_REQ ${id}] Processing auth verify request from client: ${wsId}`);
1833
+ logger.debug(`[AUTH_VERIFY_REQ ${id}] Token present: ${!!token}`);
1834
+ logger.debug(`[AUTH_VERIFY_REQ ${id}] Token length: ${token ? token.length : 0} characters`);
1664
1835
  if (!token) {
1836
+ logger.error(`[AUTH_VERIFY_REQ ${id}] Token not found in request`);
1665
1837
  sendDataResponse3(id, {
1666
1838
  success: false,
1667
1839
  error: "Token not found"
@@ -1669,17 +1841,45 @@ async function handleAuthVerifyRequest(data, sendMessage) {
1669
1841
  return;
1670
1842
  }
1671
1843
  if (!wsId) {
1844
+ logger.error(`[AUTH_VERIFY_REQ ${id}] WebSocket ID not found in request`);
1672
1845
  sendDataResponse3(id, {
1673
1846
  success: false,
1674
1847
  error: "WebSocket ID not found"
1675
1848
  }, sendMessage, wsId);
1676
1849
  return;
1677
1850
  }
1851
+ logger.info(`[AUTH_VERIFY_REQ ${id}] Token validation starting`);
1852
+ logger.debug(`[AUTH_VERIFY_REQ ${id}] WebSocket ID: ${wsId}`);
1853
+ logger.debug(`[AUTH_VERIFY_REQ ${id}] Calling verifyAuthToken`);
1854
+ const startTime = Date.now();
1678
1855
  const authResult = verifyAuthToken(token);
1856
+ const verificationTime = Date.now() - startTime;
1857
+ logger.info(`[AUTH_VERIFY_REQ ${id}] Token verification completed in ${verificationTime}ms - ${authResult.success ? "valid" : "invalid"}`);
1858
+ if (!authResult.success) {
1859
+ logger.warn(`[AUTH_VERIFY_REQ ${id}] Token verification failed: ${authResult.error}`);
1860
+ } else {
1861
+ logger.info(`[AUTH_VERIFY_REQ ${id}] Token verified successfully for user: ${authResult.data || "unknown"}`);
1862
+ }
1863
+ logger.debug(`[AUTH_VERIFY_REQ ${id}] Sending verification response to client`);
1679
1864
  sendDataResponse3(id, authResult, sendMessage, wsId);
1865
+ logger.info(`[AUTH_VERIFY_REQ ${id}] ${authResult.success ? "\u2713" : "\u2717"} Auth verify request completed`);
1680
1866
  return;
1681
1867
  } catch (error) {
1682
- logger.error("Failed to handle auth verify request:", error);
1868
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
1869
+ const errorStack = error instanceof Error ? error.stack : void 0;
1870
+ logger.error(`[AUTH_VERIFY_REQ] Failed to handle auth verify request: ${errorMessage}`);
1871
+ logger.debug(`[AUTH_VERIFY_REQ] Error stack trace:`, errorStack);
1872
+ try {
1873
+ const parsedData = data;
1874
+ if (parsedData?.id) {
1875
+ sendDataResponse3(parsedData.id, {
1876
+ success: false,
1877
+ error: `Internal error: ${errorMessage}`
1878
+ }, sendMessage, parsedData.from?.id);
1879
+ }
1880
+ } catch (sendError) {
1881
+ logger.error("[AUTH_VERIFY_REQ] Failed to send error response:", sendError);
1882
+ }
1683
1883
  }
1684
1884
  }
1685
1885
  function sendDataResponse3(id, res, sendMessage, clientId) {
@@ -1695,6 +1895,14 @@ function sendDataResponse3(id, res, sendMessage, clientId) {
1695
1895
  ...res
1696
1896
  }
1697
1897
  };
1898
+ logger.debug(`[AUTH_VERIFY_RES ${id}] Sending ${res.success ? "successful" : "failed"} verification response to client: ${clientId}`);
1899
+ logger.debug(`[AUTH_VERIFY_RES ${id}] Response payload size: ${JSON.stringify(response).length} bytes`);
1900
+ if (res.error) {
1901
+ logger.debug(`[AUTH_VERIFY_RES ${id}] Error message: ${res.error}`);
1902
+ }
1903
+ if (res.data) {
1904
+ logger.debug(`[AUTH_VERIFY_RES ${id}] User verified: ${res.data}`);
1905
+ }
1698
1906
  sendMessage(response);
1699
1907
  }
1700
1908
 
@@ -1744,6 +1952,47 @@ function ensureQueryLimit(query, defaultLimit = 50) {
1744
1952
  }
1745
1953
  return trimmedQuery;
1746
1954
  }
1955
+ function fixScalarSubqueries(query) {
1956
+ if (!query || query.trim().length === 0) {
1957
+ return query;
1958
+ }
1959
+ let modifiedQuery = query;
1960
+ let hasChanges = false;
1961
+ const scalarOperatorPattern = /([=<>!]=?|<>)\s*\(\s*SELECT\s/gi;
1962
+ const matches = [...modifiedQuery.matchAll(scalarOperatorPattern)];
1963
+ for (let i = matches.length - 1; i >= 0; i--) {
1964
+ const match = matches[i];
1965
+ const startPos = match.index + match[0].length - "SELECT ".length;
1966
+ let parenDepth = 1;
1967
+ let endPos = startPos;
1968
+ let foundEnd = false;
1969
+ for (let j = startPos; j < modifiedQuery.length; j++) {
1970
+ const char = modifiedQuery[j];
1971
+ if (char === "(") parenDepth++;
1972
+ if (char === ")") {
1973
+ parenDepth--;
1974
+ if (parenDepth === 0) {
1975
+ endPos = j;
1976
+ foundEnd = true;
1977
+ break;
1978
+ }
1979
+ }
1980
+ }
1981
+ if (!foundEnd) continue;
1982
+ const subquery = modifiedQuery.substring(startPos, endPos);
1983
+ if (/\bLIMIT\s+\d+/i.test(subquery)) {
1984
+ continue;
1985
+ }
1986
+ const fixedSubquery = subquery.trim() + " LIMIT 1";
1987
+ modifiedQuery = modifiedQuery.substring(0, startPos) + fixedSubquery + modifiedQuery.substring(endPos);
1988
+ hasChanges = true;
1989
+ console.warn(`\u26A0\uFE0F Fixed scalar subquery: added LIMIT 1 to prevent multiple row error`);
1990
+ }
1991
+ if (hasChanges) {
1992
+ console.log("\u2713 Query validated and fixed for PostgreSQL scalar subquery compatibility");
1993
+ }
1994
+ return modifiedQuery;
1995
+ }
1747
1996
 
1748
1997
  // src/userResponse/schema.ts
1749
1998
  var import_path = __toESM(require("path"));
@@ -1906,7 +2155,8 @@ var PromptLoader = class {
1906
2155
  "single-component",
1907
2156
  "mutli-component",
1908
2157
  "actions",
1909
- "container-metadata"
2158
+ "container-metadata",
2159
+ "text-response"
1910
2160
  ];
1911
2161
  for (const promptType of promptTypes) {
1912
2162
  try {
@@ -2258,7 +2508,9 @@ var BaseLLM = class {
2258
2508
  needsMultipleComponents: result.needsMultipleComponents || false
2259
2509
  };
2260
2510
  } catch (error) {
2261
- console.error("Error classifying user question:", error);
2511
+ const errorMsg = error instanceof Error ? error.message : String(error);
2512
+ logger.error(`[${this.getProviderName()}] Error classifying user question: ${errorMsg}`);
2513
+ logger.debug(`[${this.getProviderName()}] Classification error details:`, error);
2262
2514
  throw error;
2263
2515
  }
2264
2516
  }
@@ -2296,6 +2548,7 @@ var BaseLLM = class {
2296
2548
  );
2297
2549
  const props = result.props || originalProps;
2298
2550
  if (props && props.query) {
2551
+ props.query = fixScalarSubqueries(props.query);
2299
2552
  props.query = ensureQueryLimit(props.query, this.defaultLimit);
2300
2553
  }
2301
2554
  if (props && props.query) {
@@ -2322,7 +2575,9 @@ var BaseLLM = class {
2322
2575
  modifications: result.modifications || []
2323
2576
  };
2324
2577
  } catch (error) {
2325
- console.error(`Error validating/modifying props with ${this.getProviderName()}:`, error);
2578
+ const errorMsg = error instanceof Error ? error.message : String(error);
2579
+ logger.error(`[${this.getProviderName()}] Error validating/modifying props: ${errorMsg}`);
2580
+ logger.debug(`[${this.getProviderName()}] Props validation error details:`, error);
2326
2581
  throw error;
2327
2582
  }
2328
2583
  }
@@ -2442,7 +2697,9 @@ var BaseLLM = class {
2442
2697
  isGenerated: true
2443
2698
  };
2444
2699
  } catch (error) {
2445
- console.error("Error generating analytical component:", error);
2700
+ const errorMsg = error instanceof Error ? error.message : String(error);
2701
+ logger.error(`[${this.getProviderName()}] Error generating analytical component: ${errorMsg}`);
2702
+ logger.debug(`[${this.getProviderName()}] Analytical component generation error details:`, error);
2446
2703
  throw error;
2447
2704
  }
2448
2705
  }
@@ -2484,7 +2741,9 @@ var BaseLLM = class {
2484
2741
  description: result.description || `Multi-component dashboard showing ${visualizationTypes.join(", ")}`
2485
2742
  };
2486
2743
  } catch (error) {
2487
- console.error("Error generating container metadata:", error);
2744
+ const errorMsg = error instanceof Error ? error.message : String(error);
2745
+ logger.error(`[${this.getProviderName()}] Error generating container metadata: ${errorMsg}`);
2746
+ logger.debug(`[${this.getProviderName()}] Container metadata error details:`, error);
2488
2747
  return {
2489
2748
  title: `${userPrompt} - Dashboard`,
2490
2749
  description: `Multi-component dashboard showing ${visualizationTypes.join(", ")}`
@@ -2536,24 +2795,24 @@ var BaseLLM = class {
2536
2795
  component = components[componentIndex - 1];
2537
2796
  }
2538
2797
  const matchedMsg = `${this.getProviderName()} matched component: ${component?.name || "None"}`;
2539
- console.log("\u2713", matchedMsg);
2798
+ logger.info(`[${this.getProviderName()}] \u2713 ${matchedMsg}`);
2540
2799
  logCollector?.info(matchedMsg);
2541
2800
  if (result.alternativeMatches && result.alternativeMatches.length > 0) {
2542
- console.log(" Alternative matches:");
2801
+ logger.debug(`[${this.getProviderName()}] Alternative matches found: ${result.alternativeMatches.length}`);
2543
2802
  const altMatches = result.alternativeMatches.map(
2544
2803
  (alt) => `${components[alt.index - 1]?.name} (${alt.score}%): ${alt.reason}`
2545
2804
  ).join(" | ");
2546
2805
  logCollector?.info(`Alternative matches: ${altMatches}`);
2547
2806
  result.alternativeMatches.forEach((alt) => {
2548
- console.log(` - ${components[alt.index - 1]?.name} (${alt.score}%): ${alt.reason}`);
2807
+ logger.debug(`[${this.getProviderName()}] - ${components[alt.index - 1]?.name} (${alt.score}%): ${alt.reason}`);
2549
2808
  });
2550
2809
  }
2551
2810
  if (!component) {
2552
2811
  const noMatchMsg = `No matching component found (confidence: ${confidence}%)`;
2553
- console.log("\u2717", noMatchMsg);
2812
+ logger.warn(`[${this.getProviderName()}] \u2717 ${noMatchMsg}`);
2554
2813
  logCollector?.warn(noMatchMsg);
2555
2814
  const genMsg = "Attempting to match component from analytical question...";
2556
- console.log("\u2713", genMsg);
2815
+ logger.info(`[${this.getProviderName()}] \u2713 ${genMsg}`);
2557
2816
  logCollector?.info(genMsg);
2558
2817
  const generatedResult = await this.generateAnalyticalComponent(userPrompt, components, void 0, apiKey, logCollector, conversationHistory);
2559
2818
  if (generatedResult.component) {
@@ -2614,8 +2873,10 @@ var BaseLLM = class {
2614
2873
  confidence
2615
2874
  };
2616
2875
  } catch (error) {
2617
- console.error(`Error matching component with ${this.getProviderName()}:`, error);
2618
- logCollector?.error(`Error matching component: ${error.message}`);
2876
+ const errorMsg = error instanceof Error ? error.message : String(error);
2877
+ logger.error(`[${this.getProviderName()}] Error matching component: ${errorMsg}`);
2878
+ logger.debug(`[${this.getProviderName()}] Component matching error details:`, error);
2879
+ logCollector?.error(`Error matching component: ${errorMsg}`);
2619
2880
  throw error;
2620
2881
  }
2621
2882
  }
@@ -2646,7 +2907,9 @@ var BaseLLM = class {
2646
2907
  isGenerated: true
2647
2908
  };
2648
2909
  } catch (error) {
2649
- console.error("Error matching multiple analytical components:", error);
2910
+ const errorMsg = error instanceof Error ? error.message : String(error);
2911
+ logger.error(`[${this.getProviderName()}] Error matching multiple analytical components: ${errorMsg}`);
2912
+ logger.debug(`[${this.getProviderName()}] Multiple components matching error details:`, error);
2650
2913
  return {
2651
2914
  components: [],
2652
2915
  reasoning: "Error occurred while matching components",
@@ -2725,17 +2988,91 @@ var BaseLLM = class {
2725
2988
  isGenerated: true
2726
2989
  };
2727
2990
  } catch (error) {
2728
- console.error("Error generating multi-component response:", error);
2991
+ const errorMsg = error instanceof Error ? error.message : String(error);
2992
+ logger.error(`[${this.getProviderName()}] Error generating multi-component response: ${errorMsg}`);
2993
+ logger.debug(`[${this.getProviderName()}] Multi-component response error details:`, error);
2729
2994
  throw error;
2730
2995
  }
2731
2996
  }
2732
2997
  /**
2733
- * Main orchestration function that classifies question and routes to appropriate handler
2734
- * This is the NEW recommended entry point for handling user requests
2735
- * ALWAYS returns a SINGLE component (wraps multiple in MultiComponentContainer)
2998
+ * Generate text-based response for user question
2999
+ * This provides conversational text responses instead of component generation
3000
+ */
3001
+ async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory) {
3002
+ const errors = [];
3003
+ logger.debug(`[${this.getProviderName()}] Starting text response generation`);
3004
+ logger.debug(`[${this.getProviderName()}] User prompt: "${userPrompt.substring(0, 50)}..."`);
3005
+ try {
3006
+ const prompts = await promptLoader.loadPrompts("text-response", {
3007
+ USER_PROMPT: userPrompt,
3008
+ CONVERSATION_HISTORY: conversationHistory || "No previous conversation"
3009
+ });
3010
+ logger.debug(`[${this.getProviderName()}] Loaded text-response prompts`);
3011
+ logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
3012
+ logCollector?.info("Generating text response...");
3013
+ const result = await LLM.stream(
3014
+ {
3015
+ sys: prompts.system,
3016
+ user: prompts.user
3017
+ },
3018
+ {
3019
+ model: this.model,
3020
+ maxTokens: 1e3,
3021
+ temperature: 0.7,
3022
+ apiKey: this.getApiKey(apiKey)
3023
+ },
3024
+ true
3025
+ // Parse as JSON
3026
+ );
3027
+ logger.info(`[${this.getProviderName()}] Text response generated successfully`);
3028
+ logger.debug(`[${this.getProviderName()}] Response type: ${result.responseType}, Confidence: ${result.confidence}`);
3029
+ logCollector?.info(`Text response: ${result.text?.substring(0, 100)}${result.text?.length > 100 ? "..." : ""}`);
3030
+ logCollector?.logExplanation(
3031
+ "Text response generated",
3032
+ result.reasoning || "Generated text response for user question",
3033
+ {
3034
+ responseType: result.responseType,
3035
+ confidence: result.confidence,
3036
+ textLength: result.text?.length || 0
3037
+ }
3038
+ );
3039
+ return {
3040
+ success: true,
3041
+ data: {
3042
+ text: result.text || "I apologize, but I was unable to generate a response.",
3043
+ responseType: result.responseType || "answer",
3044
+ confidence: result.confidence || 0.5,
3045
+ reasoning: result.reasoning || "No reasoning provided"
3046
+ },
3047
+ errors: []
3048
+ };
3049
+ } catch (error) {
3050
+ const errorMsg = error instanceof Error ? error.message : String(error);
3051
+ logger.error(`[${this.getProviderName()}] Error generating text response: ${errorMsg}`);
3052
+ logger.debug(`[${this.getProviderName()}] Text response generation error details:`, error);
3053
+ logCollector?.error(`Error generating text response: ${errorMsg}`);
3054
+ errors.push(errorMsg);
3055
+ return {
3056
+ success: false,
3057
+ errors,
3058
+ data: {
3059
+ text: "I apologize, but I encountered an error while processing your question. Please try rephrasing or ask something else.",
3060
+ responseType: "error",
3061
+ confidence: 0,
3062
+ reasoning: `Error: ${errorMsg}`
3063
+ }
3064
+ };
3065
+ }
3066
+ }
3067
+ /**
3068
+ * Generate component response for user question
3069
+ * This provides conversational component suggestions based on user question
3070
+ * Supports component generation and matching
2736
3071
  */
2737
- async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory) {
3072
+ async generateComponentResponse(userPrompt, components, apiKey, logCollector, conversationHistory) {
3073
+ const errors = [];
2738
3074
  try {
3075
+ logger.info(`[${this.getProviderName()}] Using component response mode`);
2739
3076
  const classifyMsg = "Classifying user question...";
2740
3077
  logCollector?.info(classifyMsg);
2741
3078
  const classification = await this.classifyUserQuestion(userPrompt, apiKey, logCollector, conversationHistory);
@@ -2772,16 +3109,20 @@ var BaseLLM = class {
2772
3109
  logCollector?.warn(`Error matching component: ${settledResult.reason?.message || "Unknown error"}`);
2773
3110
  }
2774
3111
  }
2775
- console.log("matched components: after multi comp", matchedComponents.length);
3112
+ logger.debug(`[${this.getProviderName()}] Matched ${matchedComponents.length} components for multi-component container`);
2776
3113
  if (matchedComponents.length === 0) {
2777
3114
  return {
2778
- component: null,
2779
- reasoning: "Failed to match any components for the requested visualization types",
2780
- method: "classification-multi-failed",
2781
- questionType: classification.questionType,
2782
- needsMultipleComponents: true,
2783
- propsModified: false,
2784
- queryModified: false
3115
+ success: true,
3116
+ data: {
3117
+ component: null,
3118
+ reasoning: "Failed to match any components for the requested visualization types",
3119
+ method: "classification-multi-failed",
3120
+ questionType: classification.questionType,
3121
+ needsMultipleComponents: true,
3122
+ propsModified: false,
3123
+ queryModified: false
3124
+ },
3125
+ errors: []
2785
3126
  };
2786
3127
  }
2787
3128
  logCollector?.info("Generating container metadata...");
@@ -2811,38 +3152,50 @@ var BaseLLM = class {
2811
3152
  };
2812
3153
  logCollector?.info(`Created multi-component container with ${matchedComponents.length} components: "${containerMetadata.title}"`);
2813
3154
  return {
2814
- component: containerComponent,
2815
- reasoning: `Matched ${matchedComponents.length} components for visualization types: ${classification.visualizations.join(", ")}`,
2816
- method: "classification-multi-generated",
2817
- questionType: classification.questionType,
2818
- needsMultipleComponents: true,
2819
- propsModified: false,
2820
- queryModified: false
3155
+ success: true,
3156
+ data: {
3157
+ component: containerComponent,
3158
+ reasoning: `Matched ${matchedComponents.length} components for visualization types: ${classification.visualizations.join(", ")}`,
3159
+ method: "classification-multi-generated",
3160
+ questionType: classification.questionType,
3161
+ needsMultipleComponents: true,
3162
+ propsModified: false,
3163
+ queryModified: false
3164
+ },
3165
+ errors: []
2821
3166
  };
2822
3167
  } else if (classification.visualizations.length === 1) {
2823
3168
  const vizType = classification.visualizations[0];
2824
3169
  logCollector?.info(`Matching single component for type: ${vizType}`);
2825
3170
  const result = await this.generateAnalyticalComponent(userPrompt, components, vizType, apiKey, logCollector, conversationHistory);
2826
3171
  return {
2827
- component: result.component,
2828
- reasoning: result.reasoning,
2829
- method: "classification-generated",
2830
- questionType: classification.questionType,
2831
- needsMultipleComponents: false,
2832
- propsModified: false,
2833
- queryModified: false
3172
+ success: true,
3173
+ data: {
3174
+ component: result.component,
3175
+ reasoning: result.reasoning,
3176
+ method: "classification-generated",
3177
+ questionType: classification.questionType,
3178
+ needsMultipleComponents: false,
3179
+ propsModified: false,
3180
+ queryModified: false
3181
+ },
3182
+ errors: []
2834
3183
  };
2835
3184
  } else {
2836
3185
  logCollector?.info("No specific visualization type - matching from all components");
2837
3186
  const result = await this.generateAnalyticalComponent(userPrompt, components, void 0, apiKey, logCollector, conversationHistory);
2838
3187
  return {
2839
- component: result.component,
2840
- reasoning: result.reasoning,
2841
- method: "classification-generated-auto",
2842
- questionType: classification.questionType,
2843
- needsMultipleComponents: false,
2844
- propsModified: false,
2845
- queryModified: false
3188
+ success: true,
3189
+ data: {
3190
+ component: result.component,
3191
+ reasoning: result.reasoning,
3192
+ method: "classification-generated-auto",
3193
+ questionType: classification.questionType,
3194
+ needsMultipleComponents: false,
3195
+ propsModified: false,
3196
+ queryModified: false
3197
+ },
3198
+ errors: []
2846
3199
  };
2847
3200
  }
2848
3201
  } else if (classification.questionType === "data_modification" || classification.questionType === "general") {
@@ -2850,28 +3203,109 @@ var BaseLLM = class {
2850
3203
  logCollector?.info(matchMsg);
2851
3204
  const matchResult = await this.matchComponent(userPrompt, components, apiKey, logCollector, conversationHistory);
2852
3205
  return {
2853
- component: matchResult.component,
2854
- reasoning: matchResult.reasoning,
2855
- method: "classification-matched",
2856
- questionType: classification.questionType,
2857
- needsMultipleComponents: false,
2858
- propsModified: matchResult.propsModified,
2859
- queryModified: matchResult.queryModified
3206
+ success: true,
3207
+ data: {
3208
+ component: matchResult.component,
3209
+ reasoning: matchResult.reasoning,
3210
+ method: "classification-matched",
3211
+ questionType: classification.questionType,
3212
+ needsMultipleComponents: false,
3213
+ propsModified: matchResult.propsModified,
3214
+ queryModified: matchResult.queryModified
3215
+ },
3216
+ errors: []
2860
3217
  };
2861
3218
  } else {
2862
3219
  logCollector?.info("General question - no component needed");
2863
3220
  return {
2864
- component: null,
2865
- reasoning: "General question - no component needed",
2866
- method: "classification-general",
2867
- questionType: classification.questionType,
2868
- needsMultipleComponents: false
3221
+ success: true,
3222
+ data: {
3223
+ component: null,
3224
+ reasoning: "General question - no component needed",
3225
+ method: "classification-general",
3226
+ questionType: classification.questionType,
3227
+ needsMultipleComponents: false,
3228
+ propsModified: false,
3229
+ queryModified: false
3230
+ },
3231
+ errors: []
2869
3232
  };
2870
3233
  }
2871
3234
  } catch (error) {
2872
- logCollector?.error(`Error handling user request: ${error.message}`);
2873
- throw error;
3235
+ const errorMsg = error instanceof Error ? error.message : String(error);
3236
+ logger.error(`[${this.getProviderName()}] Error generating component response: ${errorMsg}`);
3237
+ logger.debug(`[${this.getProviderName()}] Component response generation error details:`, error);
3238
+ logCollector?.error(`Error generating component response: ${errorMsg}`);
3239
+ errors.push(errorMsg);
3240
+ return {
3241
+ success: false,
3242
+ errors,
3243
+ data: void 0
3244
+ };
3245
+ }
3246
+ }
3247
+ /**
3248
+ * Main orchestration function that classifies question and routes to appropriate handler
3249
+ * This is the NEW recommended entry point for handling user requests
3250
+ * Supports both component generation and text response modes
3251
+ *
3252
+ * @param responseMode - 'component' for component generation (default), 'text' for text responses
3253
+ */
3254
+ async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") {
3255
+ logger.info(`[${this.getProviderName()}] handleUserRequest called with responseMode: ${responseMode}`);
3256
+ if (responseMode === "text") {
3257
+ logger.info(`[${this.getProviderName()}] Using text response mode`);
3258
+ logCollector?.info("Generating text response...");
3259
+ const textResponse = await this.generateTextResponse(
3260
+ userPrompt,
3261
+ apiKey,
3262
+ logCollector,
3263
+ conversationHistory
3264
+ );
3265
+ if (!textResponse.success) {
3266
+ logger.error(`[${this.getProviderName()}] Text response generation failed`);
3267
+ return textResponse;
3268
+ }
3269
+ logger.info(`[${this.getProviderName()}] Text response generated successfully`);
3270
+ return {
3271
+ success: true,
3272
+ data: {
3273
+ textResponse: textResponse.data.text,
3274
+ text: textResponse.data.text,
3275
+ responseType: textResponse.data.responseType,
3276
+ confidence: textResponse.data.confidence,
3277
+ reasoning: textResponse.data.reasoning,
3278
+ method: `${this.getProviderName()}-text-response`
3279
+ },
3280
+ errors: []
3281
+ };
2874
3282
  }
3283
+ const componentResponse = await this.generateComponentResponse(
3284
+ userPrompt,
3285
+ components,
3286
+ apiKey,
3287
+ logCollector,
3288
+ conversationHistory
3289
+ );
3290
+ if (!componentResponse.success) {
3291
+ logger.error(`[${this.getProviderName()}] Component response generation failed`);
3292
+ return componentResponse;
3293
+ }
3294
+ logger.info(`[${this.getProviderName()}] Component response generated successfully`);
3295
+ return {
3296
+ success: true,
3297
+ data: {
3298
+ component: componentResponse.data.component,
3299
+ reasoning: componentResponse.data.reasoning,
3300
+ method: componentResponse.data.method,
3301
+ // Preserve the original method name
3302
+ questionType: componentResponse.data.questionType,
3303
+ needsMultipleComponents: componentResponse.data.needsMultipleComponents,
3304
+ propsModified: componentResponse.data.propsModified,
3305
+ queryModified: componentResponse.data.queryModified
3306
+ },
3307
+ errors: []
3308
+ };
2875
3309
  }
2876
3310
  /**
2877
3311
  * Generate next questions that the user might ask based on the original prompt and generated component
@@ -2917,8 +3351,10 @@ var BaseLLM = class {
2917
3351
  );
2918
3352
  return nextQuestions;
2919
3353
  } catch (error) {
2920
- console.error(`Error generating next questions with ${this.getProviderName()}:`, error);
2921
- logCollector?.error(`Error generating next questions: ${error.message}`);
3354
+ const errorMsg = error instanceof Error ? error.message : String(error);
3355
+ logger.error(`[${this.getProviderName()}] Error generating next questions: ${errorMsg}`);
3356
+ logger.debug(`[${this.getProviderName()}] Next questions generation error details:`, error);
3357
+ logCollector?.error(`Error generating next questions: ${errorMsg}`);
2922
3358
  return [];
2923
3359
  }
2924
3360
  }
@@ -2982,112 +3418,130 @@ function getLLMProviders() {
2982
3418
  return DEFAULT_PROVIDERS;
2983
3419
  }
2984
3420
  }
2985
- var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory) => {
2986
- const msg = "Using Anthropic Claude matching method...";
2987
- console.log(msg);
3421
+ var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") => {
3422
+ logger.debug("[useAnthropicMethod] Initializing Anthropic Claude matching method");
3423
+ logger.debug(`[useAnthropicMethod] Response mode: ${responseMode}`);
3424
+ const msg = `Using Anthropic Claude ${responseMode === "text" ? "text response" : "matching"} method...`;
2988
3425
  logCollector?.info(msg);
2989
- if (components.length === 0) {
3426
+ if (responseMode === "component" && components.length === 0) {
2990
3427
  const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
3428
+ logger.error("[useAnthropicMethod] No components available");
2991
3429
  logCollector?.error(emptyMsg);
2992
- return { success: false, reason: emptyMsg };
2993
- }
2994
- try {
2995
- const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory);
2996
- return { success: true, data: matchResult };
2997
- } catch (error) {
2998
- const errorMsg = error instanceof Error ? error.message : String(error);
2999
- logCollector?.error(`Anthropic method failed: ${errorMsg}`);
3000
- throw error;
3430
+ return { success: false, errors: [emptyMsg] };
3001
3431
  }
3432
+ logger.debug(`[useAnthropicMethod] Processing with ${components.length} components`);
3433
+ const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode);
3434
+ logger.info(`[useAnthropicMethod] Successfully generated ${responseMode} using Anthropic`);
3435
+ return matchResult;
3002
3436
  };
3003
- var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory) => {
3004
- const msg = "Using Groq LLM matching method...";
3005
- console.log(msg);
3437
+ var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") => {
3438
+ logger.debug("[useGroqMethod] Initializing Groq LLM matching method");
3439
+ logger.debug(`[useGroqMethod] Response mode: ${responseMode}`);
3440
+ const msg = `Using Groq LLM ${responseMode === "text" ? "text response" : "matching"} method...`;
3441
+ logger.info(msg);
3006
3442
  logCollector?.info(msg);
3007
- if (components.length === 0) {
3443
+ if (responseMode === "component" && components.length === 0) {
3008
3444
  const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
3445
+ logger.error("[useGroqMethod] No components available");
3009
3446
  logCollector?.error(emptyMsg);
3010
- return { success: false, reason: emptyMsg };
3011
- }
3012
- try {
3013
- const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory);
3014
- return { success: true, data: matchResult };
3015
- } catch (error) {
3016
- const errorMsg = error instanceof Error ? error.message : String(error);
3017
- logCollector?.error(`Groq method failed: ${errorMsg}`);
3018
- throw error;
3447
+ return { success: false, errors: [emptyMsg] };
3019
3448
  }
3449
+ logger.debug(`[useGroqMethod] Processing with ${components.length} components`);
3450
+ const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode);
3451
+ logger.info(`[useGroqMethod] Successfully generated ${responseMode} using Groq`);
3452
+ return matchResult;
3020
3453
  };
3021
3454
  var getUserResponseFromCache = async (prompt) => {
3022
3455
  return false;
3023
3456
  };
3024
3457
  var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory) => {
3458
+ const responseMode = "component";
3459
+ logger.debug(`[get_user_response] Starting user response generation for prompt: "${prompt.substring(0, 50)}..."`);
3460
+ logger.debug("[get_user_response] Checking cache for existing response");
3025
3461
  const userResponse = await getUserResponseFromCache(prompt);
3026
3462
  if (userResponse) {
3463
+ logger.info("[get_user_response] User response found in cache - returning cached result");
3027
3464
  logCollector?.info("User response found in cache");
3028
3465
  return {
3029
3466
  success: true,
3030
- data: userResponse
3467
+ data: userResponse,
3468
+ errors: []
3031
3469
  };
3032
3470
  }
3471
+ logger.debug("[get_user_response] No cached response found, proceeding with LLM providers");
3033
3472
  const providers = llmProviders || getLLMProviders();
3034
3473
  const errors = [];
3035
3474
  const providerOrder = providers.join(", ");
3036
3475
  logCollector?.info(`LLM Provider order: [${providerOrder}]`);
3037
3476
  if (conversationHistory && conversationHistory.length > 0) {
3038
- logCollector?.info(`Using conversation history with ${conversationHistory.split("\n").filter((l) => l.startsWith("Q")).length} previous exchanges`);
3477
+ const exchangeCount = conversationHistory.split("\n").filter((l) => l.startsWith("Q")).length;
3478
+ logger.debug(`[get_user_response] Using conversation history with ${exchangeCount} previous exchanges`);
3479
+ logCollector?.info(`Using conversation history with ${exchangeCount} previous exchanges`);
3480
+ } else {
3481
+ logger.debug("[get_user_response] No conversation history available");
3039
3482
  }
3040
3483
  for (let i = 0; i < providers.length; i++) {
3041
3484
  const provider = providers[i];
3042
3485
  const isLastProvider = i === providers.length - 1;
3043
- try {
3044
- const attemptMsg = `Attempting provider: ${provider} (${i + 1}/${providers.length})`;
3045
- logCollector?.info(attemptMsg);
3046
- let result;
3047
- if (provider === "anthropic") {
3048
- result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory);
3049
- } else if (provider === "groq") {
3050
- result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory);
3051
- } else {
3052
- continue;
3053
- }
3054
- if (result.success) {
3055
- const successMsg = `Success with provider: ${provider}`;
3056
- logCollector?.info(successMsg);
3057
- return result;
3058
- } else {
3059
- errors.push({ provider, error: result.reason || "Unknown error" });
3060
- const warnMsg = `Provider ${provider} returned unsuccessful result: ${result.reason}`;
3061
- logCollector?.warn(warnMsg);
3062
- }
3063
- } catch (error) {
3064
- const errorMessage = error.message;
3065
- errors.push({ provider, error: errorMessage });
3066
- const errorMsg = `Provider ${provider} failed: ${errorMessage}`;
3067
- logCollector?.error(errorMsg);
3486
+ const attemptMsg = `Attempting provider: ${provider} (${i + 1}/${providers.length})`;
3487
+ logCollector?.info(attemptMsg);
3488
+ let result;
3489
+ if (provider === "anthropic") {
3490
+ result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory, responseMode);
3491
+ } else if (provider === "groq") {
3492
+ result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory, responseMode);
3493
+ } else {
3494
+ logger.warn(`[get_user_response] Unknown provider: ${provider} - skipping`);
3495
+ errors.push(`Unknown provider: ${provider}`);
3496
+ continue;
3497
+ }
3498
+ if (result.success) {
3499
+ const successMsg = `Success with provider: ${provider} result: ${JSON.stringify(result)}`;
3500
+ logger.info(`${successMsg}`);
3501
+ logCollector?.info(successMsg);
3502
+ return result;
3503
+ } else {
3504
+ const providerErrors = result.errors.map((err) => `${provider}: ${err}`);
3505
+ errors.push(...providerErrors);
3506
+ const warnMsg = `Provider ${provider} returned unsuccessful result: ${result.errors.join(", ")}`;
3507
+ logger.warn(`[get_user_response] ${warnMsg}`);
3508
+ logCollector?.warn(warnMsg);
3068
3509
  if (!isLastProvider) {
3069
3510
  const fallbackMsg = "Falling back to next provider...";
3511
+ logger.info(`[get_user_response] ${fallbackMsg}`);
3070
3512
  logCollector?.info(fallbackMsg);
3071
- continue;
3072
3513
  }
3073
3514
  }
3074
3515
  }
3075
- const errorSummary = errors.map((e) => `${e.provider}: ${e.error}`).join("; ");
3076
- const failureMsg = `All LLM providers failed. Errors: ${errorSummary}`;
3077
- logCollector?.error(failureMsg);
3516
+ const failureMsg = `All LLM providers failed`;
3517
+ logger.error(`[get_user_response] ${failureMsg}. Errors: ${errors.join("; ")}`);
3518
+ logCollector?.error(`${failureMsg}. Errors: ${errors.join("; ")}`);
3078
3519
  return {
3079
3520
  success: false,
3080
- reason: failureMsg
3521
+ errors
3081
3522
  };
3082
3523
  };
3083
3524
 
3084
3525
  // src/utils/log-collector.ts
3526
+ var LOG_LEVEL_PRIORITY2 = {
3527
+ errors: 0,
3528
+ warnings: 1,
3529
+ info: 2,
3530
+ verbose: 3
3531
+ };
3532
+ var MESSAGE_LEVEL_PRIORITY2 = {
3533
+ error: 0,
3534
+ warn: 1,
3535
+ info: 2,
3536
+ debug: 3
3537
+ };
3085
3538
  var UILogCollector = class {
3086
3539
  constructor(clientId, sendMessage, uiBlockId) {
3087
3540
  this.logs = [];
3088
3541
  this.uiBlockId = uiBlockId || null;
3089
3542
  this.clientId = clientId;
3090
3543
  this.sendMessage = sendMessage;
3544
+ this.currentLogLevel = logger.getLogLevel();
3091
3545
  }
3092
3546
  /**
3093
3547
  * Check if logging is enabled (uiBlockId is provided)
@@ -3095,10 +3549,22 @@ var UILogCollector = class {
3095
3549
  isEnabled() {
3096
3550
  return this.uiBlockId !== null;
3097
3551
  }
3552
+ /**
3553
+ * Check if a message should be logged based on current log level
3554
+ */
3555
+ shouldLog(messageLevel) {
3556
+ const currentLevelPriority = LOG_LEVEL_PRIORITY2[this.currentLogLevel];
3557
+ const messagePriority = MESSAGE_LEVEL_PRIORITY2[messageLevel];
3558
+ return messagePriority <= currentLevelPriority;
3559
+ }
3098
3560
  /**
3099
3561
  * Add a log entry with timestamp and immediately send to runtime
3562
+ * Only logs that pass the log level filter are captured and sent
3100
3563
  */
3101
3564
  addLog(level, message, type, data) {
3565
+ if (!this.shouldLog(level)) {
3566
+ return;
3567
+ }
3102
3568
  const log = {
3103
3569
  timestamp: Date.now(),
3104
3570
  level,
@@ -3108,7 +3574,20 @@ var UILogCollector = class {
3108
3574
  };
3109
3575
  this.logs.push(log);
3110
3576
  this.sendLogImmediately(log);
3111
- console.log("UILogCollector:", log);
3577
+ switch (level) {
3578
+ case "error":
3579
+ logger.error("UILogCollector:", log);
3580
+ break;
3581
+ case "warn":
3582
+ logger.warn("UILogCollector:", log);
3583
+ break;
3584
+ case "info":
3585
+ logger.info("UILogCollector:", log);
3586
+ break;
3587
+ case "debug":
3588
+ logger.debug("UILogCollector:", log);
3589
+ break;
3590
+ }
3112
3591
  }
3113
3592
  /**
3114
3593
  * Send a single log to runtime immediately
@@ -3239,102 +3718,131 @@ var CONTEXT_CONFIG = {
3239
3718
 
3240
3719
  // src/handlers/user-prompt-request.ts
3241
3720
  var processedMessageIds = /* @__PURE__ */ new Set();
3242
- async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders) {
3243
- try {
3244
- const userPromptRequest = UserPromptRequestMessageSchema.parse(data);
3245
- const { id, payload } = userPromptRequest;
3246
- const prompt = payload.prompt;
3247
- const SA_RUNTIME = payload.SA_RUNTIME;
3248
- const wsId = userPromptRequest.from.id || "unknown";
3249
- logger.info(`[REQUEST ${id}] Processing user prompt: "${prompt.substring(0, 50)}..."`);
3250
- if (processedMessageIds.has(id)) {
3251
- logger.warn(`[REQUEST ${id}] Duplicate request detected - ignoring`);
3252
- return;
3253
- }
3254
- processedMessageIds.add(id);
3255
- if (processedMessageIds.size > 100) {
3256
- const firstId = processedMessageIds.values().next().value;
3257
- if (firstId) {
3258
- processedMessageIds.delete(firstId);
3721
+ var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders) => {
3722
+ const errors = [];
3723
+ logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
3724
+ const parseResult = UserPromptRequestMessageSchema.safeParse(data);
3725
+ if (!parseResult.success) {
3726
+ const zodError = parseResult.error;
3727
+ zodError.errors.forEach((err) => {
3728
+ errors.push(`${err.path.join(".")}: ${err.message}`);
3729
+ });
3730
+ return { success: false, errors };
3731
+ }
3732
+ const userPromptRequest = parseResult.data;
3733
+ const { id, payload } = userPromptRequest;
3734
+ const prompt = payload.prompt;
3735
+ const SA_RUNTIME = payload.SA_RUNTIME;
3736
+ const wsId = userPromptRequest.from.id || "unknown";
3737
+ logger.debug(`[REQUEST ${id}] Full request details - wsId: ${wsId}, prompt length: ${prompt.length}`);
3738
+ if (processedMessageIds.has(id)) {
3739
+ logger.warn(`[REQUEST ${id}] Duplicate request detected - ignoring`);
3740
+ }
3741
+ processedMessageIds.add(id);
3742
+ logger.debug(`[REQUEST ${id}] Message ID marked as processed (${processedMessageIds.size} total)`);
3743
+ if (processedMessageIds.size > 100) {
3744
+ const firstId = processedMessageIds.values().next().value;
3745
+ if (firstId) {
3746
+ processedMessageIds.delete(firstId);
3747
+ logger.debug(`[REQUEST ${id}] Cleaned up old message ID from cache`);
3748
+ }
3749
+ }
3750
+ if (!SA_RUNTIME) {
3751
+ errors.push("SA_RUNTIME is required");
3752
+ }
3753
+ const threadId = SA_RUNTIME?.threadId;
3754
+ const existingUiBlockId = SA_RUNTIME?.uiBlockId;
3755
+ if (!threadId) {
3756
+ errors.push("threadId in SA_RUNTIME is required");
3757
+ }
3758
+ if (!existingUiBlockId) {
3759
+ errors.push("uiBlockId in SA_RUNTIME is required");
3760
+ }
3761
+ if (!prompt) {
3762
+ errors.push("Prompt not found");
3763
+ }
3764
+ if (!components || components.length === 0) {
3765
+ errors.push("Components not found");
3766
+ }
3767
+ if (errors.length > 0) {
3768
+ return { success: false, errors, id, wsId };
3769
+ }
3770
+ const logCollector = new UILogCollector(wsId, sendMessage, existingUiBlockId);
3771
+ const threadManager = ThreadManager.getInstance();
3772
+ let thread = threadManager.getThread(threadId);
3773
+ if (!thread) {
3774
+ thread = threadManager.createThread(threadId);
3775
+ logger.info(`Created new thread: ${threadId}`);
3776
+ }
3777
+ logCollector.info(`Starting user prompt request with ${components.length} components`);
3778
+ const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
3779
+ logger.info("conversationHistory", conversationHistory);
3780
+ const userResponse = await get_user_response(prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory);
3781
+ logger.info("llm userResponse", userResponse);
3782
+ logCollector.info("User prompt request completed");
3783
+ const uiBlockId = existingUiBlockId;
3784
+ if (!userResponse.success) {
3785
+ logger.error(`User prompt request failed with errors: ${userResponse.errors.join(", ")}`);
3786
+ return {
3787
+ success: false,
3788
+ data: userResponse.data,
3789
+ errors: userResponse.errors,
3790
+ uiBlockId,
3791
+ threadId,
3792
+ id,
3793
+ wsId
3794
+ };
3795
+ }
3796
+ let component = null;
3797
+ let textResponse = null;
3798
+ if (userResponse.data) {
3799
+ if (typeof userResponse.data === "object") {
3800
+ if ("component" in userResponse.data) {
3801
+ component = userResponse.data.component;
3802
+ }
3803
+ if ("textResponse" in userResponse.data) {
3804
+ textResponse = userResponse.data.textResponse;
3259
3805
  }
3260
3806
  }
3261
- if (!SA_RUNTIME) {
3262
- sendDataResponse4(id, {
3263
- success: false,
3264
- error: "SA_RUNTIME is required"
3265
- }, sendMessage, wsId);
3266
- return;
3267
- }
3268
- const threadId = SA_RUNTIME.threadId;
3269
- const existingUiBlockId = SA_RUNTIME.uiBlockId;
3270
- if (!threadId) {
3271
- sendDataResponse4(id, {
3272
- success: false,
3273
- error: "threadId in SA_RUNTIME is required"
3274
- }, sendMessage, wsId);
3275
- return;
3276
- }
3277
- if (!existingUiBlockId) {
3278
- sendDataResponse4(id, {
3279
- success: false,
3280
- error: "uiBlockId in SA_RUNTIME is required"
3281
- }, sendMessage, wsId);
3282
- return;
3283
- }
3284
- const logCollector = new UILogCollector(wsId, sendMessage, existingUiBlockId);
3285
- if (!prompt) {
3286
- sendDataResponse4(id, {
3287
- success: false,
3288
- error: "Prompt not found"
3289
- }, sendMessage, wsId);
3290
- return;
3291
- }
3292
- if (!components || components.length === 0) {
3293
- sendDataResponse4(id, {
3294
- success: false,
3295
- error: "Components not found"
3296
- }, sendMessage, wsId);
3297
- return;
3298
- }
3299
- const threadManager = ThreadManager.getInstance();
3300
- let thread = threadManager.getThread(threadId);
3301
- if (!thread) {
3302
- thread = threadManager.createThread(threadId);
3303
- logger.info(`Created new thread: ${threadId}`);
3304
- }
3305
- logCollector.info(`Starting user prompt request with ${components.length} components`);
3306
- const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
3307
- logger.info("conversationHistory", conversationHistory);
3308
- const userResponse = await get_user_response(prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory);
3309
- logger.info("llm userResponse", userResponse);
3310
- logCollector.info("User prompt request completed");
3311
- if (userResponse.success && userResponse.data && typeof userResponse.data === "object" && "component" in userResponse.data) {
3312
- const component = userResponse.data.component;
3313
- const uiBlockId = existingUiBlockId;
3314
- const uiBlock = new UIBlock(
3315
- prompt,
3316
- {},
3317
- // componentData: initially empty, will be filled later
3318
- component || {},
3319
- // generatedComponentMetadata: full component object (ComponentSchema)
3320
- [],
3321
- // actions: empty initially
3322
- uiBlockId
3323
- );
3324
- thread.addUIBlock(uiBlock);
3325
- logger.info(`Created UIBlock: ${uiBlockId} in Thread: ${threadId}`);
3326
- sendDataResponse4(id, {
3327
- ...userResponse,
3328
- uiBlockId,
3329
- threadId
3330
- }, sendMessage, wsId);
3331
- } else {
3332
- sendDataResponse4(id, userResponse, sendMessage, wsId);
3333
- }
3334
- return;
3335
- } catch (error) {
3336
- logger.error("Failed to handle user prompt request:", error);
3337
3807
  }
3808
+ const uiBlock = new UIBlock(
3809
+ prompt,
3810
+ {},
3811
+ // componentData: initially empty, will be filled later
3812
+ component,
3813
+ // generatedComponentMetadata: full component object (ComponentSchema)
3814
+ [],
3815
+ // actions: empty initially
3816
+ uiBlockId,
3817
+ textResponse
3818
+ // textResponse: text response from LLM
3819
+ );
3820
+ thread.addUIBlock(uiBlock);
3821
+ logger.info(`Created UIBlock: ${uiBlockId} in Thread: ${threadId}`);
3822
+ return {
3823
+ success: userResponse.success,
3824
+ data: userResponse.data,
3825
+ errors: userResponse.errors,
3826
+ uiBlockId,
3827
+ threadId,
3828
+ id,
3829
+ wsId
3830
+ };
3831
+ };
3832
+ async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders) {
3833
+ const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders);
3834
+ sendDataResponse4(
3835
+ response.id || data.id,
3836
+ {
3837
+ success: response.success,
3838
+ errors: response.errors,
3839
+ data: response.data,
3840
+ uiBlockId: response.uiBlockId,
3841
+ threadId: response.threadId
3842
+ },
3843
+ sendMessage,
3844
+ response.wsId || data.from?.id
3845
+ );
3338
3846
  }
3339
3847
  function sendDataResponse4(id, res, sendMessage, clientId) {
3340
3848
  const response = {
@@ -3447,12 +3955,27 @@ function sendResponse(id, res, sendMessage, clientId) {
3447
3955
  // src/userResponse/next-questions.ts
3448
3956
  async function generateNextQuestions(originalUserPrompt, component, componentData, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory) {
3449
3957
  try {
3958
+ logger.debug("[generateNextQuestions] Starting next questions generation");
3959
+ logger.debug(`[generateNextQuestions] User prompt: "${originalUserPrompt?.substring(0, 50)}..."`);
3960
+ logger.debug(`[generateNextQuestions] Component: ${component?.name || "unknown"} (${component?.type || "unknown"})`);
3961
+ logger.debug(`[generateNextQuestions] Component data available: ${componentData ? "yes" : "no"}`);
3450
3962
  const providers = llmProviders || ["anthropic"];
3451
- for (const provider of providers) {
3963
+ logger.info(`[generateNextQuestions] Using LLM providers: [${providers.join(", ")}]`);
3964
+ if (conversationHistory && conversationHistory.length > 0) {
3965
+ const exchangeCount = conversationHistory.split("\n").filter((l) => l.startsWith("Q")).length;
3966
+ logger.debug(`[generateNextQuestions] Using conversation history with ${exchangeCount} previous exchanges`);
3967
+ } else {
3968
+ logger.debug("[generateNextQuestions] No conversation history available");
3969
+ }
3970
+ for (let i = 0; i < providers.length; i++) {
3971
+ const provider = providers[i];
3972
+ const isLastProvider = i === providers.length - 1;
3452
3973
  try {
3453
- logger.info(`Generating next questions using provider: ${provider}`);
3974
+ logger.info(`[generateNextQuestions] Attempting provider: ${provider} (${i + 1}/${providers.length})`);
3975
+ logCollector?.info(`Generating questions with ${provider}...`);
3454
3976
  let result = [];
3455
3977
  if (provider === "groq") {
3978
+ logger.debug("[generateNextQuestions] Using Groq LLM for next questions");
3456
3979
  result = await groqLLM.generateNextQuestions(
3457
3980
  originalUserPrompt,
3458
3981
  component,
@@ -3462,6 +3985,7 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
3462
3985
  conversationHistory
3463
3986
  );
3464
3987
  } else {
3988
+ logger.debug("[generateNextQuestions] Using Anthropic LLM for next questions");
3465
3989
  result = await anthropicLLM.generateNextQuestions(
3466
3990
  originalUserPrompt,
3467
3991
  component,
@@ -3472,21 +3996,39 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
3472
3996
  );
3473
3997
  }
3474
3998
  if (result && result.length > 0) {
3475
- logger.info(`Successfully generated ${result.length} questions with ${provider}`);
3999
+ logger.info(`[generateNextQuestions] Successfully generated ${result.length} questions with ${provider}`);
4000
+ logger.debug(`[generateNextQuestions] Questions: ${JSON.stringify(result)}`);
4001
+ logCollector?.info(`Generated ${result.length} follow-up questions`);
3476
4002
  return result;
3477
4003
  }
3478
- logger.warn(`No questions generated from ${provider}, trying next provider...`);
4004
+ const warnMsg = `No questions generated from ${provider}${!isLastProvider ? ", trying next provider..." : ""}`;
4005
+ logger.warn(`[generateNextQuestions] ${warnMsg}`);
4006
+ if (!isLastProvider) {
4007
+ logCollector?.warn(warnMsg);
4008
+ }
3479
4009
  } catch (providerError) {
3480
- logger.warn(`Provider ${provider} failed:`, providerError);
3481
- logCollector?.warn(`Provider ${provider} failed, trying next provider...`);
4010
+ const errorMsg = providerError instanceof Error ? providerError.message : String(providerError);
4011
+ logger.error(`[generateNextQuestions] Provider ${provider} failed: ${errorMsg}`);
4012
+ logger.debug(`[generateNextQuestions] Provider error details:`, providerError);
4013
+ if (!isLastProvider) {
4014
+ const fallbackMsg = `Provider ${provider} failed, trying next provider...`;
4015
+ logger.info(`[generateNextQuestions] ${fallbackMsg}`);
4016
+ logCollector?.warn(fallbackMsg);
4017
+ } else {
4018
+ logCollector?.error(`Failed to generate questions with ${provider}`);
4019
+ }
3482
4020
  continue;
3483
4021
  }
3484
4022
  }
3485
- logger.warn("All providers failed or returned no questions");
4023
+ logger.warn("[generateNextQuestions] All providers failed or returned no questions");
4024
+ logCollector?.warn("Unable to generate follow-up questions");
3486
4025
  return [];
3487
4026
  } catch (error) {
3488
- logger.error("Error generating next questions:", error);
3489
- logCollector?.error(`Error generating next questions: ${error.message}`);
4027
+ const errorMsg = error instanceof Error ? error.message : String(error);
4028
+ const errorStack = error instanceof Error ? error.stack : void 0;
4029
+ logger.error(`[generateNextQuestions] Error generating next questions: ${errorMsg}`);
4030
+ logger.debug("[generateNextQuestions] Error stack trace:", errorStack);
4031
+ logCollector?.error(`Error generating next questions: ${errorMsg}`);
3490
4032
  return [];
3491
4033
  }
3492
4034
  }
@@ -3494,11 +4036,15 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
3494
4036
  // src/handlers/actions-request.ts
3495
4037
  async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiKey, llmProviders) {
3496
4038
  try {
4039
+ logger.debug("[ACTIONS_REQ] Parsing incoming actions request");
3497
4040
  const actionsRequest = ActionsRequestMessageSchema.parse(data);
3498
4041
  const { id, payload } = actionsRequest;
3499
4042
  const { SA_RUNTIME } = payload;
3500
4043
  const wsId = actionsRequest.from.id || "unknown";
4044
+ logger.info(`[ACTIONS_REQ ${id}] Processing actions request from client: ${wsId}`);
4045
+ logger.debug(`[ACTIONS_REQ ${id}] Request payload:`, JSON.stringify(payload, null, 2).substring(0, 200));
3501
4046
  if (!SA_RUNTIME) {
4047
+ logger.error(`[ACTIONS_REQ ${id}] SA_RUNTIME missing from request`);
3502
4048
  sendResponse2(id, {
3503
4049
  success: false,
3504
4050
  error: "SA_RUNTIME with threadId and uiBlockId is required"
@@ -3507,31 +4053,54 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
3507
4053
  }
3508
4054
  const uiBlockId = SA_RUNTIME.uiBlockId;
3509
4055
  const threadId = SA_RUNTIME.threadId;
4056
+ logger.debug(`[ACTIONS_REQ ${id}] SA_RUNTIME validated - threadId: ${threadId}, uiBlockId: ${uiBlockId}`);
4057
+ logger.debug(`[ACTIONS_REQ ${id}] Retrieving thread: ${threadId}`);
3510
4058
  const threadManager = ThreadManager.getInstance();
3511
4059
  const thread = threadManager.getThread(threadId);
3512
4060
  if (!thread) {
4061
+ logger.error(`[ACTIONS_REQ ${id}] Thread '${threadId}' not found`);
3513
4062
  sendResponse2(id, {
3514
4063
  success: false,
3515
4064
  error: `Thread '${threadId}' not found`
3516
4065
  }, sendMessage, wsId);
3517
4066
  return;
3518
4067
  }
4068
+ logger.debug(`[ACTIONS_REQ ${id}] Thread found with ${thread.getUIBlocks().length} UIBlocks`);
4069
+ logger.debug(`[ACTIONS_REQ ${id}] Retrieving UIBlock: ${uiBlockId}`);
3519
4070
  const uiBlock = thread.getUIBlock(uiBlockId);
3520
4071
  if (!uiBlock) {
4072
+ logger.error(`[ACTIONS_REQ ${id}] UIBlock '${uiBlockId}' not found in thread '${threadId}'`);
3521
4073
  sendResponse2(id, {
3522
4074
  success: false,
3523
4075
  error: `UIBlock '${uiBlockId}' not found in thread '${threadId}'`
3524
4076
  }, sendMessage, wsId);
3525
4077
  return;
3526
4078
  }
4079
+ logger.info(`[ACTIONS_REQ ${id}] UIBlock retrieved successfully`);
4080
+ logger.debug(`[ACTIONS_REQ ${id}] Creating UILogCollector for uiBlockId: ${uiBlockId}`);
3527
4081
  const logCollector = new UILogCollector(wsId, sendMessage, uiBlockId);
4082
+ logger.info(`[ACTIONS_REQ ${id}] UILogCollector initialized`);
4083
+ logger.debug(`[ACTIONS_REQ ${id}] Extracting data from UIBlock`);
3528
4084
  const userQuestion = uiBlock.getUserQuestion();
3529
4085
  const component = uiBlock.getComponentMetadata();
3530
4086
  const componentData = uiBlock.getComponentData();
4087
+ logger.debug(`[ACTIONS_REQ ${id}] User question: "${userQuestion?.substring(0, 50)}..."`);
4088
+ logger.debug(`[ACTIONS_REQ ${id}] Component: ${component?.name || "unknown"} (${component?.type || "unknown"})`);
4089
+ logger.debug(`[ACTIONS_REQ ${id}] Component data available: ${componentData ? "yes" : "no"}`);
4090
+ logger.debug(`[ACTIONS_REQ ${id}] Extracting conversation history (max ${CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS} blocks)`);
3531
4091
  const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, uiBlockId);
4092
+ const historyLineCount = conversationHistory.split("\n").filter((l) => l.trim()).length;
4093
+ logger.info(`[ACTIONS_REQ ${id}] Conversation history extracted: ${historyLineCount} lines`);
4094
+ logger.debug(`[ACTIONS_REQ ${id}] Conversation history preview:
4095
+ ${conversationHistory.substring(0, 200)}...`);
3532
4096
  logCollector.info(`Generating actions for UIBlock: ${uiBlockId}`);
3533
- logger.info(`Generating actions for component: ${component?.name || "unknown"}`);
4097
+ logger.info(`[ACTIONS_REQ ${id}] Generating actions for component: ${component?.name || "unknown"}`);
4098
+ logger.debug(`[ACTIONS_REQ ${id}] Checking if actions are already cached`);
4099
+ const startTime = Date.now();
3534
4100
  const actions = await uiBlock.getOrFetchActions(async () => {
4101
+ logger.info(`[ACTIONS_REQ ${id}] Actions not cached, generating new actions...`);
4102
+ logCollector.info("Generating follow-up questions...");
4103
+ logger.info(`[ACTIONS_REQ ${id}] Starting next questions generation with ${llmProviders?.join(", ") || "default"} providers`);
3535
4104
  const nextQuestions = await generateNextQuestions(
3536
4105
  userQuestion,
3537
4106
  component,
@@ -3542,14 +4111,28 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
3542
4111
  logCollector,
3543
4112
  conversationHistory
3544
4113
  );
3545
- return nextQuestions.map((question, index) => ({
4114
+ logger.info(`[ACTIONS_REQ ${id}] Generated ${nextQuestions.length} questions`);
4115
+ logger.debug(`[ACTIONS_REQ ${id}] Questions: ${JSON.stringify(nextQuestions)}`);
4116
+ logger.debug(`[ACTIONS_REQ ${id}] Converting questions to actions format`);
4117
+ const convertedActions = nextQuestions.map((question, index) => ({
3546
4118
  id: `action_${index}_${Date.now()}`,
3547
4119
  name: question,
3548
4120
  type: "next_question",
3549
4121
  question
3550
4122
  }));
4123
+ logger.debug(`[ACTIONS_REQ ${id}] Converted ${convertedActions.length} actions`);
4124
+ return convertedActions;
3551
4125
  });
3552
- logCollector.info(`Generated ${actions.length} actions successfully`);
4126
+ const processingTime = Date.now() - startTime;
4127
+ logger.info(`[ACTIONS_REQ ${id}] Actions retrieved in ${processingTime}ms - ${actions.length} actions total`);
4128
+ if (actions.length > 0) {
4129
+ logCollector.info(`Generated ${actions.length} follow-up questions successfully`);
4130
+ logger.debug(`[ACTIONS_REQ ${id}] Actions: ${actions.map((a) => a.name).join(", ")}`);
4131
+ } else {
4132
+ logger.warn(`[ACTIONS_REQ ${id}] No actions generated`);
4133
+ logCollector.warn("No follow-up questions could be generated");
4134
+ }
4135
+ logger.debug(`[ACTIONS_REQ ${id}] Sending successful response to client`);
3553
4136
  sendResponse2(id, {
3554
4137
  success: true,
3555
4138
  data: {
@@ -3560,12 +4143,26 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
3560
4143
  threadId
3561
4144
  }
3562
4145
  }, sendMessage, wsId);
4146
+ logger.info(`[ACTIONS_REQ ${id}] \u2713 Actions request completed successfully`);
3563
4147
  } catch (error) {
3564
- logger.error("Failed to handle actions request:", error);
4148
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
4149
+ const errorStack = error instanceof Error ? error.stack : void 0;
4150
+ logger.error(`[ACTIONS_REQ] Failed to handle actions request: ${errorMessage}`);
4151
+ logger.debug(`[ACTIONS_REQ] Error stack trace:`, errorStack);
4152
+ try {
4153
+ const parsedData = data;
4154
+ if (parsedData?.id && parsedData?.from?.id) {
4155
+ const logCollector = parsedData?.payload?.SA_RUNTIME?.uiBlockId ? new UILogCollector(parsedData.from.id, sendMessage, parsedData.payload.SA_RUNTIME.uiBlockId) : void 0;
4156
+ logCollector?.error(`Failed to generate actions: ${errorMessage}`);
4157
+ }
4158
+ } catch (logError) {
4159
+ logger.debug("[ACTIONS_REQ] Failed to send error logs to UI:", logError);
4160
+ }
3565
4161
  sendResponse2(null, {
3566
4162
  success: false,
3567
- error: error instanceof Error ? error.message : "Unknown error occurred"
4163
+ error: errorMessage
3568
4164
  }, sendMessage);
4165
+ logger.info("[ACTIONS_REQ] \u2717 Actions request completed with errors");
3569
4166
  }
3570
4167
  }
3571
4168
  function sendResponse2(id, res, sendMessage, clientId) {
@@ -3581,6 +4178,11 @@ function sendResponse2(id, res, sendMessage, clientId) {
3581
4178
  ...res
3582
4179
  }
3583
4180
  };
4181
+ logger.debug(`[ACTIONS_RES ${id || "unknown"}] Sending ${res.success ? "successful" : "failed"} response to client`);
4182
+ logger.debug(`[ACTIONS_RES ${id || "unknown"}] Response payload size: ${JSON.stringify(response).length} bytes`);
4183
+ if (res.data?.actions) {
4184
+ logger.debug(`[ACTIONS_RES ${id || "unknown"}] Sending ${res.data.actions.length} actions`);
4185
+ }
3584
4186
  sendMessage(response);
3585
4187
  }
3586
4188
 
@@ -3609,7 +4211,10 @@ async function handleUsersRequest(data, sendMessage) {
3609
4211
  const { id, payload, from } = request;
3610
4212
  const { operation, data: requestData } = payload;
3611
4213
  const username = requestData?.username;
4214
+ const email = requestData?.email;
3612
4215
  const password = requestData?.password;
4216
+ const fullname = requestData?.fullname;
4217
+ const role = requestData?.role;
3613
4218
  if (from.type !== "admin") {
3614
4219
  sendResponse3(id, {
3615
4220
  success: false,
@@ -3621,10 +4226,10 @@ async function handleUsersRequest(data, sendMessage) {
3621
4226
  const userManager = getUserManager();
3622
4227
  switch (operation) {
3623
4228
  case "create":
3624
- await handleCreate(id, username, password, userManager, sendMessage, from.id);
4229
+ await handleCreate(id, { username, email, password, fullname, role }, userManager, sendMessage, from.id);
3625
4230
  break;
3626
4231
  case "update":
3627
- await handleUpdate(id, username, password, userManager, sendMessage, from.id);
4232
+ await handleUpdate(id, { username, email, password, fullname, role }, userManager, sendMessage, from.id);
3628
4233
  break;
3629
4234
  case "delete":
3630
4235
  await handleDelete(id, username, userManager, sendMessage, from.id);
@@ -3649,7 +4254,8 @@ async function handleUsersRequest(data, sendMessage) {
3649
4254
  }, sendMessage);
3650
4255
  }
3651
4256
  }
3652
- async function handleCreate(id, username, password, userManager, sendMessage, clientId) {
4257
+ async function handleCreate(id, userData, userManager, sendMessage, clientId) {
4258
+ const { username, email, password, fullname, role } = userData;
3653
4259
  if (!username || username.trim().length === 0) {
3654
4260
  sendResponse3(id, {
3655
4261
  success: false,
@@ -3664,6 +4270,16 @@ async function handleCreate(id, username, password, userManager, sendMessage, cl
3664
4270
  }, sendMessage, clientId);
3665
4271
  return;
3666
4272
  }
4273
+ if (email && email.trim().length > 0) {
4274
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
4275
+ if (!emailRegex.test(email)) {
4276
+ sendResponse3(id, {
4277
+ success: false,
4278
+ error: "Invalid email format"
4279
+ }, sendMessage, clientId);
4280
+ return;
4281
+ }
4282
+ }
3667
4283
  if (userManager.userExists(username)) {
3668
4284
  sendResponse3(id, {
3669
4285
  success: false,
@@ -3671,25 +4287,41 @@ async function handleCreate(id, username, password, userManager, sendMessage, cl
3671
4287
  }, sendMessage, clientId);
3672
4288
  return;
3673
4289
  }
3674
- let wsIds = [];
3675
- if (clientId) {
3676
- wsIds.push(clientId);
4290
+ if (email && userManager.getUserByEmail(email)) {
4291
+ sendResponse3(id, {
4292
+ success: false,
4293
+ error: `User with email '${email}' already exists`
4294
+ }, sendMessage, clientId);
4295
+ return;
3677
4296
  }
3678
- const newUser = userManager.createUser({
4297
+ const newUserData = {
3679
4298
  username,
3680
- password,
3681
- wsIds
3682
- });
3683
- logger.info(`User created by admin: ${username}`);
4299
+ password
4300
+ };
4301
+ if (email && email.trim().length > 0) {
4302
+ newUserData.email = email.trim();
4303
+ }
4304
+ if (fullname && fullname.trim().length > 0) {
4305
+ newUserData.fullname = fullname.trim();
4306
+ }
4307
+ if (role && role.trim().length > 0) {
4308
+ newUserData.role = role.trim();
4309
+ }
4310
+ const newUser = userManager.createUser(newUserData);
4311
+ logger.info(`User created by admin: ${username}${email ? ` (${email})` : ""}`);
3684
4312
  sendResponse3(id, {
3685
4313
  success: true,
3686
4314
  data: {
3687
4315
  username: newUser.username,
4316
+ email: newUser.email,
4317
+ fullname: newUser.fullname,
4318
+ role: newUser.role,
3688
4319
  message: `User '${username}' created successfully`
3689
4320
  }
3690
4321
  }, sendMessage, clientId);
3691
4322
  }
3692
- async function handleUpdate(id, username, password, userManager, sendMessage, clientId) {
4323
+ async function handleUpdate(id, userData, userManager, sendMessage, clientId) {
4324
+ const { username, email, password, fullname, role } = userData;
3693
4325
  if (!username || username.trim().length === 0) {
3694
4326
  sendResponse3(id, {
3695
4327
  success: false,
@@ -3705,13 +4337,42 @@ async function handleUpdate(id, username, password, userManager, sendMessage, cl
3705
4337
  return;
3706
4338
  }
3707
4339
  const updates = {};
3708
- if (password && password.trim().length > 0) {
3709
- updates.password = password;
4340
+ if (email !== void 0) {
4341
+ if (email.trim().length > 0) {
4342
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
4343
+ if (!emailRegex.test(email)) {
4344
+ sendResponse3(id, {
4345
+ success: false,
4346
+ error: "Invalid email format"
4347
+ }, sendMessage, clientId);
4348
+ return;
4349
+ }
4350
+ const existingUser = userManager.getUserByEmail(email);
4351
+ if (existingUser && existingUser.username !== username) {
4352
+ sendResponse3(id, {
4353
+ success: false,
4354
+ error: `Email '${email}' is already used by another user`
4355
+ }, sendMessage, clientId);
4356
+ return;
4357
+ }
4358
+ updates.email = email.trim();
4359
+ } else {
4360
+ updates.email = void 0;
4361
+ }
4362
+ }
4363
+ if (password !== void 0 && password.trim().length > 0) {
4364
+ updates.password = password.trim();
4365
+ }
4366
+ if (fullname !== void 0) {
4367
+ updates.fullname = fullname.trim().length > 0 ? fullname.trim() : void 0;
4368
+ }
4369
+ if (role !== void 0) {
4370
+ updates.role = role.trim().length > 0 ? role.trim() : void 0;
3710
4371
  }
3711
4372
  if (Object.keys(updates).length === 0) {
3712
4373
  sendResponse3(id, {
3713
4374
  success: false,
3714
- error: "No fields to update. Please provide password or other valid fields."
4375
+ error: "No fields to update. Please provide at least one field to update."
3715
4376
  }, sendMessage, clientId);
3716
4377
  return;
3717
4378
  }
@@ -3721,6 +4382,9 @@ async function handleUpdate(id, username, password, userManager, sendMessage, cl
3721
4382
  success: true,
3722
4383
  data: {
3723
4384
  username: updatedUser.username,
4385
+ email: updatedUser.email,
4386
+ fullname: updatedUser.fullname,
4387
+ role: updatedUser.role,
3724
4388
  message: `User '${username}' updated successfully`
3725
4389
  }
3726
4390
  }, sendMessage, clientId);
@@ -3761,6 +4425,9 @@ async function handleGetAll(id, userManager, sendMessage, clientId) {
3761
4425
  const users = userManager.getAllUsers();
3762
4426
  const sanitizedUsers = users.map((user) => ({
3763
4427
  username: user.username,
4428
+ email: user.email,
4429
+ fullname: user.fullname,
4430
+ role: user.role,
3764
4431
  wsIds: user.wsIds || []
3765
4432
  }));
3766
4433
  logger.info(`Admin retrieved all users (count: ${sanitizedUsers.length})`);
@@ -3791,6 +4458,9 @@ async function handleGetOne(id, username, userManager, sendMessage, clientId) {
3791
4458
  const user = userManager.getUser(username);
3792
4459
  const sanitizedUser = {
3793
4460
  username: user.username,
4461
+ email: user.email,
4462
+ fullname: user.fullname,
4463
+ role: user.role,
3794
4464
  wsIds: user.wsIds || []
3795
4465
  };
3796
4466
  logger.info(`Admin retrieved user: ${username}`);
@@ -4289,8 +4959,9 @@ var UserManager = class {
4289
4959
  return;
4290
4960
  }
4291
4961
  const fileContent = import_fs3.default.readFileSync(this.filePath, "utf-8");
4292
- const data = JSON.parse(fileContent);
4293
- this.users = Array.isArray(data.users) ? data.users : [];
4962
+ const rawData = JSON.parse(fileContent);
4963
+ const validatedData = UsersDataSchema.parse(rawData);
4964
+ this.users = validatedData.users;
4294
4965
  this.hasChanged = false;
4295
4966
  logger.debug(`Loaded ${this.users.length} users from file`);
4296
4967
  } catch (error) {
@@ -4310,10 +4981,14 @@ var UserManager = class {
4310
4981
  if (!import_fs3.default.existsSync(dir)) {
4311
4982
  import_fs3.default.mkdirSync(dir, { recursive: true });
4312
4983
  }
4313
- const data = { users: this.users };
4984
+ const usersToSave = this.users.map((user) => {
4985
+ const { wsIds, ...userWithoutWsIds } = user;
4986
+ return userWithoutWsIds;
4987
+ });
4988
+ const data = { users: usersToSave };
4314
4989
  import_fs3.default.writeFileSync(this.filePath, JSON.stringify(data, null, 4));
4315
4990
  this.hasChanged = false;
4316
- logger.debug(`Synced ${this.users.length} users to file`);
4991
+ logger.debug(`Synced ${this.users.length} users to file (wsIds excluded)`);
4317
4992
  } catch (error) {
4318
4993
  logger.error("Failed to save users to file:", error);
4319
4994
  throw new Error(`Failed to save users to file: ${error instanceof Error ? error.message : "Unknown error"}`);
@@ -4360,13 +5035,17 @@ var UserManager = class {
4360
5035
  * @returns The created user
4361
5036
  */
4362
5037
  createUser(user) {
4363
- if (this.users.some((u) => u.username === user.username)) {
4364
- throw new Error(`User with username ${user.username} already exists`);
5038
+ const validatedUser = UserSchema.parse(user);
5039
+ if (this.users.some((u) => u.username === validatedUser.username)) {
5040
+ throw new Error(`User with username ${validatedUser.username} already exists`);
5041
+ }
5042
+ if (validatedUser.email && this.users.some((u) => u.email === validatedUser.email)) {
5043
+ throw new Error(`User with email ${validatedUser.email} already exists`);
4365
5044
  }
4366
- this.users.push(user);
5045
+ this.users.push(validatedUser);
4367
5046
  this.hasChanged = true;
4368
- logger.debug(`User created: ${user.username}`);
4369
- return user;
5047
+ logger.debug(`User created: ${validatedUser.username}`);
5048
+ return validatedUser;
4370
5049
  }
4371
5050
  /**
4372
5051
  * Read a user by username
@@ -4376,6 +5055,22 @@ var UserManager = class {
4376
5055
  getUser(username) {
4377
5056
  return this.users.find((u) => u.username === username);
4378
5057
  }
5058
+ /**
5059
+ * Read a user by email
5060
+ * @param email - Email to retrieve
5061
+ * @returns The user if found, undefined otherwise
5062
+ */
5063
+ getUserByEmail(email) {
5064
+ return this.users.find((u) => u.email === email);
5065
+ }
5066
+ /**
5067
+ * Find user by username or email
5068
+ * @param identifier - Username or email to search for
5069
+ * @returns The user if found, undefined otherwise
5070
+ */
5071
+ getUserByUsernameOrEmail(identifier) {
5072
+ return this.users.find((u) => u.username === identifier || u.email === identifier);
5073
+ }
4379
5074
  /**
4380
5075
  * Read all users
4381
5076
  * @returns Array of all users
@@ -4464,7 +5159,6 @@ var UserManager = class {
4464
5159
  }
4465
5160
  if (!user.wsIds.includes(wsId)) {
4466
5161
  user.wsIds.push(wsId);
4467
- this.hasChanged = true;
4468
5162
  logger.debug(`WebSocket ID added to user ${username}: ${wsId}`);
4469
5163
  }
4470
5164
  return true;
@@ -4486,7 +5180,6 @@ var UserManager = class {
4486
5180
  const initialLength = user.wsIds.length;
4487
5181
  user.wsIds = user.wsIds.filter((id) => id !== wsId);
4488
5182
  if (user.wsIds.length < initialLength) {
4489
- this.hasChanged = true;
4490
5183
  logger.debug(`WebSocket ID removed from user ${username}: ${wsId}`);
4491
5184
  }
4492
5185
  return true;
@@ -5036,6 +5729,9 @@ var SuperatomSDK = class {
5036
5729
  this.maxReconnectAttempts = 5;
5037
5730
  this.collections = {};
5038
5731
  this.components = [];
5732
+ if (config.logLevel) {
5733
+ logger.setLogLevel(config.logLevel);
5734
+ }
5039
5735
  this.apiKey = config.apiKey;
5040
5736
  this.projectId = config.projectId;
5041
5737
  this.userId = config.userId || "anonymous";
@@ -5339,6 +6035,7 @@ var SuperatomSDK = class {
5339
6035
  ThreadManager,
5340
6036
  UIBlock,
5341
6037
  UILogCollector,
5342
- UserManager
6038
+ UserManager,
6039
+ logger
5343
6040
  });
5344
6041
  //# sourceMappingURL=index.js.map