@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/README.md +74 -25
- package/dist/index.d.mts +150 -11
- package/dist/index.d.ts +150 -11
- package/dist/index.js +998 -301
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +996 -300
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
debug:
|
|
821
|
-
|
|
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
|
|
1602
|
+
function findUserByUsernameOrEmail(identifier) {
|
|
1501
1603
|
const manager = getUserManager();
|
|
1502
|
-
const user = manager.
|
|
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
|
-
|
|
1526
|
-
|
|
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
|
-
|
|
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 - ${
|
|
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.
|
|
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
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2798
|
+
logger.info(`[${this.getProviderName()}] \u2713 ${matchedMsg}`);
|
|
2540
2799
|
logCollector?.info(matchedMsg);
|
|
2541
2800
|
if (result.alternativeMatches && result.alternativeMatches.length > 0) {
|
|
2542
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2812
|
+
logger.warn(`[${this.getProviderName()}] \u2717 ${noMatchMsg}`);
|
|
2554
2813
|
logCollector?.warn(noMatchMsg);
|
|
2555
2814
|
const genMsg = "Attempting to match component from analytical question...";
|
|
2556
|
-
|
|
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
|
-
|
|
2618
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
2734
|
-
* This
|
|
2735
|
-
|
|
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
|
|
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
|
-
|
|
3112
|
+
logger.debug(`[${this.getProviderName()}] Matched ${matchedComponents.length} components for multi-component container`);
|
|
2776
3113
|
if (matchedComponents.length === 0) {
|
|
2777
3114
|
return {
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
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
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
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
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
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
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
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
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
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
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
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
|
-
|
|
2873
|
-
|
|
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
|
-
|
|
2921
|
-
|
|
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
|
-
|
|
2987
|
-
|
|
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,
|
|
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
|
-
|
|
3005
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
}
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
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
|
|
3076
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
const
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
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
|
-
|
|
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(`
|
|
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
|
-
|
|
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
|
-
|
|
3481
|
-
|
|
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
|
-
|
|
3489
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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,
|
|
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
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
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
|
|
4297
|
+
const newUserData = {
|
|
3679
4298
|
username,
|
|
3680
|
-
password
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
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,
|
|
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 (
|
|
3709
|
-
|
|
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
|
|
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
|
|
4293
|
-
|
|
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
|
|
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
|
-
|
|
4364
|
-
|
|
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(
|
|
5045
|
+
this.users.push(validatedUser);
|
|
4367
5046
|
this.hasChanged = true;
|
|
4368
|
-
logger.debug(`User created: ${
|
|
4369
|
-
return
|
|
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
|