@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.mjs
CHANGED
|
@@ -624,6 +624,18 @@ var DSLRendererPropsSchema2 = z2.object({
|
|
|
624
624
|
});
|
|
625
625
|
|
|
626
626
|
// src/types.ts
|
|
627
|
+
var UserSchema = z3.object({
|
|
628
|
+
username: z3.string().min(1, "Username is required"),
|
|
629
|
+
email: z3.string().email("Invalid email format").optional(),
|
|
630
|
+
password: z3.string().min(1, "Password is required"),
|
|
631
|
+
fullname: z3.string().optional(),
|
|
632
|
+
role: z3.string().optional(),
|
|
633
|
+
wsIds: z3.array(z3.string()).optional()
|
|
634
|
+
// Only in memory, not persisted to file
|
|
635
|
+
});
|
|
636
|
+
var UsersDataSchema = z3.object({
|
|
637
|
+
users: z3.array(UserSchema)
|
|
638
|
+
});
|
|
627
639
|
var MessageParticipantSchema = z3.object({
|
|
628
640
|
id: z3.string().optional(),
|
|
629
641
|
type: z3.string().optional()
|
|
@@ -724,7 +736,10 @@ var UsersRequestPayloadSchema = z3.object({
|
|
|
724
736
|
operation: z3.enum(["create", "update", "delete", "getAll", "getOne"]),
|
|
725
737
|
data: z3.object({
|
|
726
738
|
username: z3.string().optional(),
|
|
727
|
-
|
|
739
|
+
email: z3.string().email("Invalid email format").optional(),
|
|
740
|
+
password: z3.string().optional(),
|
|
741
|
+
fullname: z3.string().optional(),
|
|
742
|
+
role: z3.string().optional()
|
|
728
743
|
}).optional()
|
|
729
744
|
});
|
|
730
745
|
var UsersRequestMessageSchema = z3.object({
|
|
@@ -790,20 +805,91 @@ var ReportsRequestMessageSchema = z3.object({
|
|
|
790
805
|
|
|
791
806
|
// src/utils/logger.ts
|
|
792
807
|
var PREFIX = "[SuperatomSDK]";
|
|
793
|
-
var
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
debug:
|
|
804
|
-
|
|
808
|
+
var LOG_LEVEL_PRIORITY = {
|
|
809
|
+
errors: 0,
|
|
810
|
+
warnings: 1,
|
|
811
|
+
info: 2,
|
|
812
|
+
verbose: 3
|
|
813
|
+
};
|
|
814
|
+
var MESSAGE_LEVEL_PRIORITY = {
|
|
815
|
+
error: 0,
|
|
816
|
+
warn: 1,
|
|
817
|
+
info: 2,
|
|
818
|
+
debug: 3
|
|
819
|
+
};
|
|
820
|
+
var Logger = class {
|
|
821
|
+
constructor() {
|
|
822
|
+
const envLevel = (process.env.SUPERATOM_LOG_LEVEL || "info").toLowerCase();
|
|
823
|
+
if (this.isValidLogLevel(envLevel)) {
|
|
824
|
+
this.currentLevel = envLevel;
|
|
825
|
+
} else {
|
|
826
|
+
this.currentLevel = "info";
|
|
827
|
+
console.warn(
|
|
828
|
+
`${PREFIX} Invalid log level "${envLevel}". Using default "info". Valid levels: errors, warnings, info, verbose`
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
this.currentLevelPriority = LOG_LEVEL_PRIORITY[this.currentLevel];
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Check if a string is a valid log level
|
|
835
|
+
*/
|
|
836
|
+
isValidLogLevel(level) {
|
|
837
|
+
return level === "errors" || level === "warnings" || level === "info" || level === "verbose";
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Check if a message should be logged based on current log level
|
|
841
|
+
*/
|
|
842
|
+
shouldLog(messageLevel) {
|
|
843
|
+
const messagePriority = MESSAGE_LEVEL_PRIORITY[messageLevel];
|
|
844
|
+
return messagePriority <= this.currentLevelPriority;
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Get current log level
|
|
848
|
+
*/
|
|
849
|
+
getLogLevel() {
|
|
850
|
+
return this.currentLevel;
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Set log level programmatically
|
|
854
|
+
*/
|
|
855
|
+
setLogLevel(level) {
|
|
856
|
+
this.currentLevel = level;
|
|
857
|
+
this.currentLevelPriority = LOG_LEVEL_PRIORITY[level];
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Log info message (shown for info and verbose levels)
|
|
861
|
+
*/
|
|
862
|
+
info(...args) {
|
|
863
|
+
if (this.shouldLog("info")) {
|
|
864
|
+
console.log(PREFIX, ...args);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Log error message (shown for all levels)
|
|
869
|
+
*/
|
|
870
|
+
error(...args) {
|
|
871
|
+
if (this.shouldLog("error")) {
|
|
872
|
+
console.error(PREFIX, ...args);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Log warning message (shown for warnings, info, and verbose levels)
|
|
877
|
+
*/
|
|
878
|
+
warn(...args) {
|
|
879
|
+
if (this.shouldLog("warn")) {
|
|
880
|
+
console.warn(PREFIX, ...args);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Log debug message (only shown for verbose level)
|
|
885
|
+
*/
|
|
886
|
+
debug(...args) {
|
|
887
|
+
if (this.shouldLog("debug")) {
|
|
888
|
+
console.log(PREFIX, "[DEBUG]", ...args);
|
|
889
|
+
}
|
|
805
890
|
}
|
|
806
891
|
};
|
|
892
|
+
var logger = new Logger();
|
|
807
893
|
|
|
808
894
|
// src/threads/uiblock.ts
|
|
809
895
|
import { randomUUID } from "crypto";
|
|
@@ -838,13 +924,15 @@ var UIBlock = class {
|
|
|
838
924
|
* @param generatedComponentMetadata - Optional metadata about the generated component
|
|
839
925
|
* @param actions - Optional array of available actions
|
|
840
926
|
* @param id - Optional custom ID, generates UUID if not provided
|
|
927
|
+
* @param textResponse - Optional text response from LLM
|
|
841
928
|
*/
|
|
842
|
-
constructor(userQuestion, componentData = {}, generatedComponentMetadata = {}, actions = [], id) {
|
|
929
|
+
constructor(userQuestion, componentData = {}, generatedComponentMetadata = {}, actions = [], id, textResponse = null) {
|
|
843
930
|
this.id = id || randomUUID();
|
|
844
931
|
this.userQuestion = userQuestion;
|
|
845
932
|
this.componentData = componentData;
|
|
846
933
|
this.generatedComponentMetadata = generatedComponentMetadata;
|
|
847
934
|
this.actions = actions;
|
|
935
|
+
this.textResponse = textResponse;
|
|
848
936
|
this.createdAt = /* @__PURE__ */ new Date();
|
|
849
937
|
}
|
|
850
938
|
/**
|
|
@@ -963,6 +1051,18 @@ var UIBlock = class {
|
|
|
963
1051
|
const processedData = this.processDataForStorage(data);
|
|
964
1052
|
this.componentData = { ...this.componentData, ...processedData };
|
|
965
1053
|
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Get text response
|
|
1056
|
+
*/
|
|
1057
|
+
getTextResponse() {
|
|
1058
|
+
return this.textResponse;
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Set or update text response
|
|
1062
|
+
*/
|
|
1063
|
+
setTextResponse(textResponse) {
|
|
1064
|
+
this.textResponse = textResponse;
|
|
1065
|
+
}
|
|
966
1066
|
/**
|
|
967
1067
|
* Get all actions (only if they are resolved, not if fetching)
|
|
968
1068
|
*/
|
|
@@ -1046,6 +1146,7 @@ var UIBlock = class {
|
|
|
1046
1146
|
userQuestion: this.userQuestion,
|
|
1047
1147
|
generatedComponentMetadata: this.generatedComponentMetadata,
|
|
1048
1148
|
componentData: this.componentData,
|
|
1149
|
+
textResponse: this.textResponse,
|
|
1049
1150
|
actions: actionsValue,
|
|
1050
1151
|
isFetchingActions: this.actions instanceof Promise,
|
|
1051
1152
|
createdAt: this.createdAt.toISOString()
|
|
@@ -1480,9 +1581,9 @@ function getUserManager() {
|
|
|
1480
1581
|
}
|
|
1481
1582
|
return currentUserManager;
|
|
1482
1583
|
}
|
|
1483
|
-
function
|
|
1584
|
+
function findUserByUsernameOrEmail(identifier) {
|
|
1484
1585
|
const manager = getUserManager();
|
|
1485
|
-
const user = manager.
|
|
1586
|
+
const user = manager.getUserByUsernameOrEmail(identifier);
|
|
1486
1587
|
return user || null;
|
|
1487
1588
|
}
|
|
1488
1589
|
function addWsIdToUser(username, wsId) {
|
|
@@ -1504,60 +1605,81 @@ async function cleanupUserStorage() {
|
|
|
1504
1605
|
|
|
1505
1606
|
// src/auth/validator.ts
|
|
1506
1607
|
function validateUser(credentials) {
|
|
1507
|
-
const { username, password } = credentials;
|
|
1508
|
-
|
|
1509
|
-
|
|
1608
|
+
const { username, email, password } = credentials;
|
|
1609
|
+
const identifier = username || email;
|
|
1610
|
+
logger.debug("[validateUser] Starting user validation");
|
|
1611
|
+
logger.debug(`[validateUser] Username provided: ${username ? "\u2713" : "\u2717"}, Email provided: ${email ? "\u2713" : "\u2717"}, Password provided: ${password ? "\u2713" : "\u2717"}`);
|
|
1612
|
+
if (!identifier || !password) {
|
|
1613
|
+
logger.warn("[validateUser] Validation failed: Username/email and password are required");
|
|
1510
1614
|
return {
|
|
1511
1615
|
success: false,
|
|
1512
|
-
error: "Username and password are required"
|
|
1616
|
+
error: "Username or email and password are required"
|
|
1513
1617
|
};
|
|
1514
1618
|
}
|
|
1515
|
-
|
|
1619
|
+
logger.debug(`[validateUser] Looking up user by identifier: ${identifier}`);
|
|
1620
|
+
const user = findUserByUsernameOrEmail(identifier);
|
|
1516
1621
|
if (!user) {
|
|
1517
|
-
logger.warn(`Validation failed: User not found - ${
|
|
1622
|
+
logger.warn(`[validateUser] Validation failed: User not found - ${identifier}`);
|
|
1518
1623
|
return {
|
|
1519
1624
|
success: false,
|
|
1520
|
-
error: "Invalid username"
|
|
1625
|
+
error: "Invalid username or email"
|
|
1521
1626
|
};
|
|
1522
1627
|
}
|
|
1628
|
+
logger.debug(`[validateUser] User found: ${user.username}, verifying password`);
|
|
1523
1629
|
const hashedPassword = hashPassword(user.password);
|
|
1524
1630
|
if (hashedPassword !== password) {
|
|
1525
|
-
logger.warn(`Validation failed: Invalid password for user - ${username}`);
|
|
1631
|
+
logger.warn(`[validateUser] Validation failed: Invalid password for user - ${user.username}`);
|
|
1632
|
+
logger.debug(`[validateUser] Password hash mismatch for user: ${user.username}`);
|
|
1526
1633
|
return {
|
|
1527
1634
|
success: false,
|
|
1528
1635
|
error: "Invalid password"
|
|
1529
1636
|
};
|
|
1530
1637
|
}
|
|
1531
|
-
logger.
|
|
1638
|
+
logger.info(`[validateUser] \u2713 User validated successfully: ${user.username}`);
|
|
1639
|
+
logger.debug(`[validateUser] Returning user data for: ${user.username}`);
|
|
1532
1640
|
return {
|
|
1533
1641
|
success: true,
|
|
1534
|
-
data: user.username
|
|
1642
|
+
data: user.username,
|
|
1643
|
+
username: user.username
|
|
1535
1644
|
};
|
|
1536
1645
|
}
|
|
1537
1646
|
function authenticateAndStoreWsId(credentials, wsId) {
|
|
1647
|
+
const identifier = credentials.username || credentials.email;
|
|
1648
|
+
logger.debug("[authenticateAndStoreWsId] Starting authentication and WebSocket ID storage");
|
|
1649
|
+
logger.debug("[authenticateAndStoreWsId] Validating user credentials");
|
|
1538
1650
|
const validationResult = validateUser(credentials);
|
|
1539
1651
|
if (!validationResult.success) {
|
|
1652
|
+
logger.warn(`[authenticateAndStoreWsId] User validation failed for: ${identifier}`);
|
|
1540
1653
|
return validationResult;
|
|
1541
1654
|
}
|
|
1542
|
-
const
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
error: "Failed to store user session"
|
|
1548
|
-
};
|
|
1549
|
-
}
|
|
1550
|
-
logger.info(`WebSocket ID stored for user: ${credentials.username}`);
|
|
1655
|
+
const username = validationResult.username;
|
|
1656
|
+
logger.info(`[authenticateAndStoreWsId] User ${username} validated, storing WebSocket ID`);
|
|
1657
|
+
logger.debug(`[authenticateAndStoreWsId] Calling addWsIdToUser for ${username}`);
|
|
1658
|
+
addWsIdToUser(username, wsId);
|
|
1659
|
+
logger.debug(`[authenticateAndStoreWsId] WebSocket ID ${wsId} associated with user ${username}`);
|
|
1551
1660
|
return validationResult;
|
|
1552
1661
|
}
|
|
1553
1662
|
function verifyAuthToken(authToken) {
|
|
1554
1663
|
try {
|
|
1664
|
+
logger.debug("[verifyAuthToken] Starting token verification");
|
|
1665
|
+
logger.debug("[verifyAuthToken] Decoding base64 token");
|
|
1555
1666
|
const decodedString = Buffer.from(authToken, "base64").toString("utf-8");
|
|
1667
|
+
logger.debug("[verifyAuthToken] Parsing decoded token as JSON");
|
|
1556
1668
|
const credentials = JSON.parse(decodedString);
|
|
1557
|
-
logger.debug("Token decoded and parsed successfully");
|
|
1558
|
-
|
|
1669
|
+
logger.debug("[verifyAuthToken] Token decoded and parsed successfully");
|
|
1670
|
+
logger.debug(`[verifyAuthToken] Token contains username: ${credentials.username ? "\u2713" : "\u2717"}`);
|
|
1671
|
+
logger.debug("[verifyAuthToken] Validating credentials from token");
|
|
1672
|
+
const result = validateUser(credentials);
|
|
1673
|
+
if (result.success) {
|
|
1674
|
+
logger.info(`[verifyAuthToken] \u2713 Token verified successfully for user: ${credentials.username || "unknown"}`);
|
|
1675
|
+
} else {
|
|
1676
|
+
logger.warn(`[verifyAuthToken] Token verification failed: ${result.error}`);
|
|
1677
|
+
}
|
|
1678
|
+
return result;
|
|
1559
1679
|
} catch (error) {
|
|
1560
|
-
|
|
1680
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
1681
|
+
logger.error(`[verifyAuthToken] Failed to verify auth token: ${errorMsg}`);
|
|
1682
|
+
logger.debug("[verifyAuthToken] Token verification error details:", error);
|
|
1561
1683
|
return {
|
|
1562
1684
|
success: false,
|
|
1563
1685
|
error: "Invalid token format"
|
|
@@ -1568,36 +1690,49 @@ function verifyAuthToken(authToken) {
|
|
|
1568
1690
|
// src/handlers/auth-login-requests.ts
|
|
1569
1691
|
async function handleAuthLoginRequest(data, sendMessage) {
|
|
1570
1692
|
try {
|
|
1693
|
+
logger.debug("[AUTH_LOGIN_REQ] Parsing incoming auth login request");
|
|
1571
1694
|
const authRequest = AuthLoginRequestMessageSchema.parse(data);
|
|
1572
1695
|
const { id, payload } = authRequest;
|
|
1573
1696
|
const login_data = payload.login_data;
|
|
1574
1697
|
const wsId = authRequest.from.id;
|
|
1698
|
+
logger.info(`[AUTH_LOGIN_REQ ${id}] Processing auth login request from client: ${wsId}`);
|
|
1699
|
+
logger.debug(`[AUTH_LOGIN_REQ ${id}] Login data present: ${!!login_data}`);
|
|
1575
1700
|
if (!login_data) {
|
|
1701
|
+
logger.error(`[AUTH_LOGIN_REQ ${id}] Login data not found in request`);
|
|
1576
1702
|
sendDataResponse2(id, {
|
|
1577
1703
|
success: false,
|
|
1578
1704
|
error: "Login data not found"
|
|
1579
1705
|
}, sendMessage, wsId);
|
|
1580
1706
|
return;
|
|
1581
1707
|
}
|
|
1708
|
+
logger.debug(`[AUTH_LOGIN_REQ ${id}] Decoding base64 login data`);
|
|
1582
1709
|
let loginData;
|
|
1583
1710
|
try {
|
|
1584
1711
|
loginData = decodeBase64ToJson(login_data);
|
|
1712
|
+
logger.debug(`[AUTH_LOGIN_REQ ${id}] Login data decoded successfully`);
|
|
1585
1713
|
} catch (error) {
|
|
1714
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
1715
|
+
logger.error(`[AUTH_LOGIN_REQ ${id}] Failed to decode login data: ${errorMsg}`);
|
|
1716
|
+
logger.debug(`[AUTH_LOGIN_REQ ${id}] Decode error details:`, error);
|
|
1586
1717
|
sendDataResponse2(id, {
|
|
1587
1718
|
success: false,
|
|
1588
1719
|
error: "Invalid login data format"
|
|
1589
1720
|
}, sendMessage, wsId);
|
|
1590
1721
|
return;
|
|
1591
1722
|
}
|
|
1592
|
-
const { username, password } = loginData;
|
|
1593
|
-
|
|
1723
|
+
const { username, email, password } = loginData;
|
|
1724
|
+
const identifier = username || email;
|
|
1725
|
+
logger.debug(`[AUTH_LOGIN_REQ ${id}] Validating credentials - username: ${username ? "\u2713" : "\u2717"}, email: ${email ? "\u2713" : "\u2717"}, password: ${password ? "\u2713" : "\u2717"}`);
|
|
1726
|
+
if (!identifier) {
|
|
1727
|
+
logger.error(`[AUTH_LOGIN_REQ ${id}] Username or email not found in login data`);
|
|
1594
1728
|
sendDataResponse2(id, {
|
|
1595
1729
|
success: false,
|
|
1596
|
-
error: "Username
|
|
1730
|
+
error: "Username or email is required"
|
|
1597
1731
|
}, sendMessage, wsId);
|
|
1598
1732
|
return;
|
|
1599
1733
|
}
|
|
1600
1734
|
if (!password) {
|
|
1735
|
+
logger.error(`[AUTH_LOGIN_REQ ${id}] Password not found in login data`);
|
|
1601
1736
|
sendDataResponse2(id, {
|
|
1602
1737
|
success: false,
|
|
1603
1738
|
error: "Password not found in login data"
|
|
@@ -1605,20 +1740,46 @@ async function handleAuthLoginRequest(data, sendMessage) {
|
|
|
1605
1740
|
return;
|
|
1606
1741
|
}
|
|
1607
1742
|
if (!wsId) {
|
|
1743
|
+
logger.error(`[AUTH_LOGIN_REQ ${id}] WebSocket ID not found in request`);
|
|
1608
1744
|
sendDataResponse2(id, {
|
|
1609
1745
|
success: false,
|
|
1610
1746
|
error: "WebSocket ID not found"
|
|
1611
1747
|
}, sendMessage, wsId);
|
|
1612
1748
|
return;
|
|
1613
1749
|
}
|
|
1750
|
+
logger.info(`[AUTH_LOGIN_REQ ${id}] Credentials validated, authenticating user: ${identifier}`);
|
|
1751
|
+
logger.debug(`[AUTH_LOGIN_REQ ${id}] WebSocket ID: ${wsId}`);
|
|
1752
|
+
logger.debug(`[AUTH_LOGIN_REQ ${id}] Calling authenticateAndStoreWsId for user: ${identifier}`);
|
|
1614
1753
|
const authResult = authenticateAndStoreWsId(
|
|
1615
|
-
{ username, password },
|
|
1754
|
+
{ username, email, password },
|
|
1616
1755
|
wsId
|
|
1617
1756
|
);
|
|
1757
|
+
logger.info(`[AUTH_LOGIN_REQ ${id}] Authentication result for ${identifier}: ${authResult.success ? "success" : "failed"}`);
|
|
1758
|
+
if (!authResult.success) {
|
|
1759
|
+
logger.warn(`[AUTH_LOGIN_REQ ${id}] Authentication failed for ${identifier}: ${authResult.error}`);
|
|
1760
|
+
} else {
|
|
1761
|
+
logger.info(`[AUTH_LOGIN_REQ ${id}] User ${authResult.username || identifier} authenticated successfully`);
|
|
1762
|
+
}
|
|
1763
|
+
logger.debug(`[AUTH_LOGIN_REQ ${id}] Sending auth response to client`);
|
|
1618
1764
|
sendDataResponse2(id, authResult, sendMessage, wsId);
|
|
1765
|
+
logger.info(`[AUTH_LOGIN_REQ ${id}] ${authResult.success ? "\u2713" : "\u2717"} Auth login request completed`);
|
|
1619
1766
|
return;
|
|
1620
1767
|
} catch (error) {
|
|
1621
|
-
|
|
1768
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1769
|
+
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
1770
|
+
logger.error(`[AUTH_LOGIN_REQ] Failed to handle auth login request: ${errorMessage}`);
|
|
1771
|
+
logger.debug(`[AUTH_LOGIN_REQ] Error stack trace:`, errorStack);
|
|
1772
|
+
try {
|
|
1773
|
+
const parsedData = data;
|
|
1774
|
+
if (parsedData?.id) {
|
|
1775
|
+
sendDataResponse2(parsedData.id, {
|
|
1776
|
+
success: false,
|
|
1777
|
+
error: `Internal error: ${errorMessage}`
|
|
1778
|
+
}, sendMessage, parsedData.from?.id);
|
|
1779
|
+
}
|
|
1780
|
+
} catch (sendError) {
|
|
1781
|
+
logger.error("[AUTH_LOGIN_REQ] Failed to send error response:", sendError);
|
|
1782
|
+
}
|
|
1622
1783
|
}
|
|
1623
1784
|
}
|
|
1624
1785
|
function sendDataResponse2(id, res, sendMessage, clientId) {
|
|
@@ -1634,17 +1795,27 @@ function sendDataResponse2(id, res, sendMessage, clientId) {
|
|
|
1634
1795
|
...res
|
|
1635
1796
|
}
|
|
1636
1797
|
};
|
|
1798
|
+
logger.debug(`[AUTH_LOGIN_RES ${id}] Sending ${res.success ? "successful" : "failed"} auth response to client: ${clientId}`);
|
|
1799
|
+
logger.debug(`[AUTH_LOGIN_RES ${id}] Response payload size: ${JSON.stringify(response).length} bytes`);
|
|
1800
|
+
if (res.error) {
|
|
1801
|
+
logger.debug(`[AUTH_LOGIN_RES ${id}] Error message: ${res.error}`);
|
|
1802
|
+
}
|
|
1637
1803
|
sendMessage(response);
|
|
1638
1804
|
}
|
|
1639
1805
|
|
|
1640
1806
|
// src/handlers/auth-verify-request.ts
|
|
1641
1807
|
async function handleAuthVerifyRequest(data, sendMessage) {
|
|
1642
1808
|
try {
|
|
1809
|
+
logger.debug("[AUTH_VERIFY_REQ] Parsing incoming auth verify request");
|
|
1643
1810
|
const authRequest = AuthVerifyRequestMessageSchema.parse(data);
|
|
1644
1811
|
const { id, payload } = authRequest;
|
|
1645
1812
|
const token = payload.token;
|
|
1646
1813
|
const wsId = authRequest.from.id;
|
|
1814
|
+
logger.info(`[AUTH_VERIFY_REQ ${id}] Processing auth verify request from client: ${wsId}`);
|
|
1815
|
+
logger.debug(`[AUTH_VERIFY_REQ ${id}] Token present: ${!!token}`);
|
|
1816
|
+
logger.debug(`[AUTH_VERIFY_REQ ${id}] Token length: ${token ? token.length : 0} characters`);
|
|
1647
1817
|
if (!token) {
|
|
1818
|
+
logger.error(`[AUTH_VERIFY_REQ ${id}] Token not found in request`);
|
|
1648
1819
|
sendDataResponse3(id, {
|
|
1649
1820
|
success: false,
|
|
1650
1821
|
error: "Token not found"
|
|
@@ -1652,17 +1823,45 @@ async function handleAuthVerifyRequest(data, sendMessage) {
|
|
|
1652
1823
|
return;
|
|
1653
1824
|
}
|
|
1654
1825
|
if (!wsId) {
|
|
1826
|
+
logger.error(`[AUTH_VERIFY_REQ ${id}] WebSocket ID not found in request`);
|
|
1655
1827
|
sendDataResponse3(id, {
|
|
1656
1828
|
success: false,
|
|
1657
1829
|
error: "WebSocket ID not found"
|
|
1658
1830
|
}, sendMessage, wsId);
|
|
1659
1831
|
return;
|
|
1660
1832
|
}
|
|
1833
|
+
logger.info(`[AUTH_VERIFY_REQ ${id}] Token validation starting`);
|
|
1834
|
+
logger.debug(`[AUTH_VERIFY_REQ ${id}] WebSocket ID: ${wsId}`);
|
|
1835
|
+
logger.debug(`[AUTH_VERIFY_REQ ${id}] Calling verifyAuthToken`);
|
|
1836
|
+
const startTime = Date.now();
|
|
1661
1837
|
const authResult = verifyAuthToken(token);
|
|
1838
|
+
const verificationTime = Date.now() - startTime;
|
|
1839
|
+
logger.info(`[AUTH_VERIFY_REQ ${id}] Token verification completed in ${verificationTime}ms - ${authResult.success ? "valid" : "invalid"}`);
|
|
1840
|
+
if (!authResult.success) {
|
|
1841
|
+
logger.warn(`[AUTH_VERIFY_REQ ${id}] Token verification failed: ${authResult.error}`);
|
|
1842
|
+
} else {
|
|
1843
|
+
logger.info(`[AUTH_VERIFY_REQ ${id}] Token verified successfully for user: ${authResult.data || "unknown"}`);
|
|
1844
|
+
}
|
|
1845
|
+
logger.debug(`[AUTH_VERIFY_REQ ${id}] Sending verification response to client`);
|
|
1662
1846
|
sendDataResponse3(id, authResult, sendMessage, wsId);
|
|
1847
|
+
logger.info(`[AUTH_VERIFY_REQ ${id}] ${authResult.success ? "\u2713" : "\u2717"} Auth verify request completed`);
|
|
1663
1848
|
return;
|
|
1664
1849
|
} catch (error) {
|
|
1665
|
-
|
|
1850
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1851
|
+
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
1852
|
+
logger.error(`[AUTH_VERIFY_REQ] Failed to handle auth verify request: ${errorMessage}`);
|
|
1853
|
+
logger.debug(`[AUTH_VERIFY_REQ] Error stack trace:`, errorStack);
|
|
1854
|
+
try {
|
|
1855
|
+
const parsedData = data;
|
|
1856
|
+
if (parsedData?.id) {
|
|
1857
|
+
sendDataResponse3(parsedData.id, {
|
|
1858
|
+
success: false,
|
|
1859
|
+
error: `Internal error: ${errorMessage}`
|
|
1860
|
+
}, sendMessage, parsedData.from?.id);
|
|
1861
|
+
}
|
|
1862
|
+
} catch (sendError) {
|
|
1863
|
+
logger.error("[AUTH_VERIFY_REQ] Failed to send error response:", sendError);
|
|
1864
|
+
}
|
|
1666
1865
|
}
|
|
1667
1866
|
}
|
|
1668
1867
|
function sendDataResponse3(id, res, sendMessage, clientId) {
|
|
@@ -1678,6 +1877,14 @@ function sendDataResponse3(id, res, sendMessage, clientId) {
|
|
|
1678
1877
|
...res
|
|
1679
1878
|
}
|
|
1680
1879
|
};
|
|
1880
|
+
logger.debug(`[AUTH_VERIFY_RES ${id}] Sending ${res.success ? "successful" : "failed"} verification response to client: ${clientId}`);
|
|
1881
|
+
logger.debug(`[AUTH_VERIFY_RES ${id}] Response payload size: ${JSON.stringify(response).length} bytes`);
|
|
1882
|
+
if (res.error) {
|
|
1883
|
+
logger.debug(`[AUTH_VERIFY_RES ${id}] Error message: ${res.error}`);
|
|
1884
|
+
}
|
|
1885
|
+
if (res.data) {
|
|
1886
|
+
logger.debug(`[AUTH_VERIFY_RES ${id}] User verified: ${res.data}`);
|
|
1887
|
+
}
|
|
1681
1888
|
sendMessage(response);
|
|
1682
1889
|
}
|
|
1683
1890
|
|
|
@@ -1727,6 +1934,47 @@ function ensureQueryLimit(query, defaultLimit = 50) {
|
|
|
1727
1934
|
}
|
|
1728
1935
|
return trimmedQuery;
|
|
1729
1936
|
}
|
|
1937
|
+
function fixScalarSubqueries(query) {
|
|
1938
|
+
if (!query || query.trim().length === 0) {
|
|
1939
|
+
return query;
|
|
1940
|
+
}
|
|
1941
|
+
let modifiedQuery = query;
|
|
1942
|
+
let hasChanges = false;
|
|
1943
|
+
const scalarOperatorPattern = /([=<>!]=?|<>)\s*\(\s*SELECT\s/gi;
|
|
1944
|
+
const matches = [...modifiedQuery.matchAll(scalarOperatorPattern)];
|
|
1945
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
1946
|
+
const match = matches[i];
|
|
1947
|
+
const startPos = match.index + match[0].length - "SELECT ".length;
|
|
1948
|
+
let parenDepth = 1;
|
|
1949
|
+
let endPos = startPos;
|
|
1950
|
+
let foundEnd = false;
|
|
1951
|
+
for (let j = startPos; j < modifiedQuery.length; j++) {
|
|
1952
|
+
const char = modifiedQuery[j];
|
|
1953
|
+
if (char === "(") parenDepth++;
|
|
1954
|
+
if (char === ")") {
|
|
1955
|
+
parenDepth--;
|
|
1956
|
+
if (parenDepth === 0) {
|
|
1957
|
+
endPos = j;
|
|
1958
|
+
foundEnd = true;
|
|
1959
|
+
break;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
if (!foundEnd) continue;
|
|
1964
|
+
const subquery = modifiedQuery.substring(startPos, endPos);
|
|
1965
|
+
if (/\bLIMIT\s+\d+/i.test(subquery)) {
|
|
1966
|
+
continue;
|
|
1967
|
+
}
|
|
1968
|
+
const fixedSubquery = subquery.trim() + " LIMIT 1";
|
|
1969
|
+
modifiedQuery = modifiedQuery.substring(0, startPos) + fixedSubquery + modifiedQuery.substring(endPos);
|
|
1970
|
+
hasChanges = true;
|
|
1971
|
+
console.warn(`\u26A0\uFE0F Fixed scalar subquery: added LIMIT 1 to prevent multiple row error`);
|
|
1972
|
+
}
|
|
1973
|
+
if (hasChanges) {
|
|
1974
|
+
console.log("\u2713 Query validated and fixed for PostgreSQL scalar subquery compatibility");
|
|
1975
|
+
}
|
|
1976
|
+
return modifiedQuery;
|
|
1977
|
+
}
|
|
1730
1978
|
|
|
1731
1979
|
// src/userResponse/schema.ts
|
|
1732
1980
|
import path2 from "path";
|
|
@@ -1889,7 +2137,8 @@ var PromptLoader = class {
|
|
|
1889
2137
|
"single-component",
|
|
1890
2138
|
"mutli-component",
|
|
1891
2139
|
"actions",
|
|
1892
|
-
"container-metadata"
|
|
2140
|
+
"container-metadata",
|
|
2141
|
+
"text-response"
|
|
1893
2142
|
];
|
|
1894
2143
|
for (const promptType of promptTypes) {
|
|
1895
2144
|
try {
|
|
@@ -2241,7 +2490,9 @@ var BaseLLM = class {
|
|
|
2241
2490
|
needsMultipleComponents: result.needsMultipleComponents || false
|
|
2242
2491
|
};
|
|
2243
2492
|
} catch (error) {
|
|
2244
|
-
|
|
2493
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2494
|
+
logger.error(`[${this.getProviderName()}] Error classifying user question: ${errorMsg}`);
|
|
2495
|
+
logger.debug(`[${this.getProviderName()}] Classification error details:`, error);
|
|
2245
2496
|
throw error;
|
|
2246
2497
|
}
|
|
2247
2498
|
}
|
|
@@ -2279,6 +2530,7 @@ var BaseLLM = class {
|
|
|
2279
2530
|
);
|
|
2280
2531
|
const props = result.props || originalProps;
|
|
2281
2532
|
if (props && props.query) {
|
|
2533
|
+
props.query = fixScalarSubqueries(props.query);
|
|
2282
2534
|
props.query = ensureQueryLimit(props.query, this.defaultLimit);
|
|
2283
2535
|
}
|
|
2284
2536
|
if (props && props.query) {
|
|
@@ -2305,7 +2557,9 @@ var BaseLLM = class {
|
|
|
2305
2557
|
modifications: result.modifications || []
|
|
2306
2558
|
};
|
|
2307
2559
|
} catch (error) {
|
|
2308
|
-
|
|
2560
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2561
|
+
logger.error(`[${this.getProviderName()}] Error validating/modifying props: ${errorMsg}`);
|
|
2562
|
+
logger.debug(`[${this.getProviderName()}] Props validation error details:`, error);
|
|
2309
2563
|
throw error;
|
|
2310
2564
|
}
|
|
2311
2565
|
}
|
|
@@ -2425,7 +2679,9 @@ var BaseLLM = class {
|
|
|
2425
2679
|
isGenerated: true
|
|
2426
2680
|
};
|
|
2427
2681
|
} catch (error) {
|
|
2428
|
-
|
|
2682
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2683
|
+
logger.error(`[${this.getProviderName()}] Error generating analytical component: ${errorMsg}`);
|
|
2684
|
+
logger.debug(`[${this.getProviderName()}] Analytical component generation error details:`, error);
|
|
2429
2685
|
throw error;
|
|
2430
2686
|
}
|
|
2431
2687
|
}
|
|
@@ -2467,7 +2723,9 @@ var BaseLLM = class {
|
|
|
2467
2723
|
description: result.description || `Multi-component dashboard showing ${visualizationTypes.join(", ")}`
|
|
2468
2724
|
};
|
|
2469
2725
|
} catch (error) {
|
|
2470
|
-
|
|
2726
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2727
|
+
logger.error(`[${this.getProviderName()}] Error generating container metadata: ${errorMsg}`);
|
|
2728
|
+
logger.debug(`[${this.getProviderName()}] Container metadata error details:`, error);
|
|
2471
2729
|
return {
|
|
2472
2730
|
title: `${userPrompt} - Dashboard`,
|
|
2473
2731
|
description: `Multi-component dashboard showing ${visualizationTypes.join(", ")}`
|
|
@@ -2519,24 +2777,24 @@ var BaseLLM = class {
|
|
|
2519
2777
|
component = components[componentIndex - 1];
|
|
2520
2778
|
}
|
|
2521
2779
|
const matchedMsg = `${this.getProviderName()} matched component: ${component?.name || "None"}`;
|
|
2522
|
-
|
|
2780
|
+
logger.info(`[${this.getProviderName()}] \u2713 ${matchedMsg}`);
|
|
2523
2781
|
logCollector?.info(matchedMsg);
|
|
2524
2782
|
if (result.alternativeMatches && result.alternativeMatches.length > 0) {
|
|
2525
|
-
|
|
2783
|
+
logger.debug(`[${this.getProviderName()}] Alternative matches found: ${result.alternativeMatches.length}`);
|
|
2526
2784
|
const altMatches = result.alternativeMatches.map(
|
|
2527
2785
|
(alt) => `${components[alt.index - 1]?.name} (${alt.score}%): ${alt.reason}`
|
|
2528
2786
|
).join(" | ");
|
|
2529
2787
|
logCollector?.info(`Alternative matches: ${altMatches}`);
|
|
2530
2788
|
result.alternativeMatches.forEach((alt) => {
|
|
2531
|
-
|
|
2789
|
+
logger.debug(`[${this.getProviderName()}] - ${components[alt.index - 1]?.name} (${alt.score}%): ${alt.reason}`);
|
|
2532
2790
|
});
|
|
2533
2791
|
}
|
|
2534
2792
|
if (!component) {
|
|
2535
2793
|
const noMatchMsg = `No matching component found (confidence: ${confidence}%)`;
|
|
2536
|
-
|
|
2794
|
+
logger.warn(`[${this.getProviderName()}] \u2717 ${noMatchMsg}`);
|
|
2537
2795
|
logCollector?.warn(noMatchMsg);
|
|
2538
2796
|
const genMsg = "Attempting to match component from analytical question...";
|
|
2539
|
-
|
|
2797
|
+
logger.info(`[${this.getProviderName()}] \u2713 ${genMsg}`);
|
|
2540
2798
|
logCollector?.info(genMsg);
|
|
2541
2799
|
const generatedResult = await this.generateAnalyticalComponent(userPrompt, components, void 0, apiKey, logCollector, conversationHistory);
|
|
2542
2800
|
if (generatedResult.component) {
|
|
@@ -2597,8 +2855,10 @@ var BaseLLM = class {
|
|
|
2597
2855
|
confidence
|
|
2598
2856
|
};
|
|
2599
2857
|
} catch (error) {
|
|
2600
|
-
|
|
2601
|
-
|
|
2858
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2859
|
+
logger.error(`[${this.getProviderName()}] Error matching component: ${errorMsg}`);
|
|
2860
|
+
logger.debug(`[${this.getProviderName()}] Component matching error details:`, error);
|
|
2861
|
+
logCollector?.error(`Error matching component: ${errorMsg}`);
|
|
2602
2862
|
throw error;
|
|
2603
2863
|
}
|
|
2604
2864
|
}
|
|
@@ -2629,7 +2889,9 @@ var BaseLLM = class {
|
|
|
2629
2889
|
isGenerated: true
|
|
2630
2890
|
};
|
|
2631
2891
|
} catch (error) {
|
|
2632
|
-
|
|
2892
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2893
|
+
logger.error(`[${this.getProviderName()}] Error matching multiple analytical components: ${errorMsg}`);
|
|
2894
|
+
logger.debug(`[${this.getProviderName()}] Multiple components matching error details:`, error);
|
|
2633
2895
|
return {
|
|
2634
2896
|
components: [],
|
|
2635
2897
|
reasoning: "Error occurred while matching components",
|
|
@@ -2708,17 +2970,91 @@ var BaseLLM = class {
|
|
|
2708
2970
|
isGenerated: true
|
|
2709
2971
|
};
|
|
2710
2972
|
} catch (error) {
|
|
2711
|
-
|
|
2973
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2974
|
+
logger.error(`[${this.getProviderName()}] Error generating multi-component response: ${errorMsg}`);
|
|
2975
|
+
logger.debug(`[${this.getProviderName()}] Multi-component response error details:`, error);
|
|
2712
2976
|
throw error;
|
|
2713
2977
|
}
|
|
2714
2978
|
}
|
|
2715
2979
|
/**
|
|
2716
|
-
*
|
|
2717
|
-
* This
|
|
2718
|
-
|
|
2980
|
+
* Generate text-based response for user question
|
|
2981
|
+
* This provides conversational text responses instead of component generation
|
|
2982
|
+
*/
|
|
2983
|
+
async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory) {
|
|
2984
|
+
const errors = [];
|
|
2985
|
+
logger.debug(`[${this.getProviderName()}] Starting text response generation`);
|
|
2986
|
+
logger.debug(`[${this.getProviderName()}] User prompt: "${userPrompt.substring(0, 50)}..."`);
|
|
2987
|
+
try {
|
|
2988
|
+
const prompts = await promptLoader.loadPrompts("text-response", {
|
|
2989
|
+
USER_PROMPT: userPrompt,
|
|
2990
|
+
CONVERSATION_HISTORY: conversationHistory || "No previous conversation"
|
|
2991
|
+
});
|
|
2992
|
+
logger.debug(`[${this.getProviderName()}] Loaded text-response prompts`);
|
|
2993
|
+
logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
|
|
2994
|
+
logCollector?.info("Generating text response...");
|
|
2995
|
+
const result = await LLM.stream(
|
|
2996
|
+
{
|
|
2997
|
+
sys: prompts.system,
|
|
2998
|
+
user: prompts.user
|
|
2999
|
+
},
|
|
3000
|
+
{
|
|
3001
|
+
model: this.model,
|
|
3002
|
+
maxTokens: 1e3,
|
|
3003
|
+
temperature: 0.7,
|
|
3004
|
+
apiKey: this.getApiKey(apiKey)
|
|
3005
|
+
},
|
|
3006
|
+
true
|
|
3007
|
+
// Parse as JSON
|
|
3008
|
+
);
|
|
3009
|
+
logger.info(`[${this.getProviderName()}] Text response generated successfully`);
|
|
3010
|
+
logger.debug(`[${this.getProviderName()}] Response type: ${result.responseType}, Confidence: ${result.confidence}`);
|
|
3011
|
+
logCollector?.info(`Text response: ${result.text?.substring(0, 100)}${result.text?.length > 100 ? "..." : ""}`);
|
|
3012
|
+
logCollector?.logExplanation(
|
|
3013
|
+
"Text response generated",
|
|
3014
|
+
result.reasoning || "Generated text response for user question",
|
|
3015
|
+
{
|
|
3016
|
+
responseType: result.responseType,
|
|
3017
|
+
confidence: result.confidence,
|
|
3018
|
+
textLength: result.text?.length || 0
|
|
3019
|
+
}
|
|
3020
|
+
);
|
|
3021
|
+
return {
|
|
3022
|
+
success: true,
|
|
3023
|
+
data: {
|
|
3024
|
+
text: result.text || "I apologize, but I was unable to generate a response.",
|
|
3025
|
+
responseType: result.responseType || "answer",
|
|
3026
|
+
confidence: result.confidence || 0.5,
|
|
3027
|
+
reasoning: result.reasoning || "No reasoning provided"
|
|
3028
|
+
},
|
|
3029
|
+
errors: []
|
|
3030
|
+
};
|
|
3031
|
+
} catch (error) {
|
|
3032
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3033
|
+
logger.error(`[${this.getProviderName()}] Error generating text response: ${errorMsg}`);
|
|
3034
|
+
logger.debug(`[${this.getProviderName()}] Text response generation error details:`, error);
|
|
3035
|
+
logCollector?.error(`Error generating text response: ${errorMsg}`);
|
|
3036
|
+
errors.push(errorMsg);
|
|
3037
|
+
return {
|
|
3038
|
+
success: false,
|
|
3039
|
+
errors,
|
|
3040
|
+
data: {
|
|
3041
|
+
text: "I apologize, but I encountered an error while processing your question. Please try rephrasing or ask something else.",
|
|
3042
|
+
responseType: "error",
|
|
3043
|
+
confidence: 0,
|
|
3044
|
+
reasoning: `Error: ${errorMsg}`
|
|
3045
|
+
}
|
|
3046
|
+
};
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
/**
|
|
3050
|
+
* Generate component response for user question
|
|
3051
|
+
* This provides conversational component suggestions based on user question
|
|
3052
|
+
* Supports component generation and matching
|
|
2719
3053
|
*/
|
|
2720
|
-
async
|
|
3054
|
+
async generateComponentResponse(userPrompt, components, apiKey, logCollector, conversationHistory) {
|
|
3055
|
+
const errors = [];
|
|
2721
3056
|
try {
|
|
3057
|
+
logger.info(`[${this.getProviderName()}] Using component response mode`);
|
|
2722
3058
|
const classifyMsg = "Classifying user question...";
|
|
2723
3059
|
logCollector?.info(classifyMsg);
|
|
2724
3060
|
const classification = await this.classifyUserQuestion(userPrompt, apiKey, logCollector, conversationHistory);
|
|
@@ -2755,16 +3091,20 @@ var BaseLLM = class {
|
|
|
2755
3091
|
logCollector?.warn(`Error matching component: ${settledResult.reason?.message || "Unknown error"}`);
|
|
2756
3092
|
}
|
|
2757
3093
|
}
|
|
2758
|
-
|
|
3094
|
+
logger.debug(`[${this.getProviderName()}] Matched ${matchedComponents.length} components for multi-component container`);
|
|
2759
3095
|
if (matchedComponents.length === 0) {
|
|
2760
3096
|
return {
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
3097
|
+
success: true,
|
|
3098
|
+
data: {
|
|
3099
|
+
component: null,
|
|
3100
|
+
reasoning: "Failed to match any components for the requested visualization types",
|
|
3101
|
+
method: "classification-multi-failed",
|
|
3102
|
+
questionType: classification.questionType,
|
|
3103
|
+
needsMultipleComponents: true,
|
|
3104
|
+
propsModified: false,
|
|
3105
|
+
queryModified: false
|
|
3106
|
+
},
|
|
3107
|
+
errors: []
|
|
2768
3108
|
};
|
|
2769
3109
|
}
|
|
2770
3110
|
logCollector?.info("Generating container metadata...");
|
|
@@ -2794,38 +3134,50 @@ var BaseLLM = class {
|
|
|
2794
3134
|
};
|
|
2795
3135
|
logCollector?.info(`Created multi-component container with ${matchedComponents.length} components: "${containerMetadata.title}"`);
|
|
2796
3136
|
return {
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
3137
|
+
success: true,
|
|
3138
|
+
data: {
|
|
3139
|
+
component: containerComponent,
|
|
3140
|
+
reasoning: `Matched ${matchedComponents.length} components for visualization types: ${classification.visualizations.join(", ")}`,
|
|
3141
|
+
method: "classification-multi-generated",
|
|
3142
|
+
questionType: classification.questionType,
|
|
3143
|
+
needsMultipleComponents: true,
|
|
3144
|
+
propsModified: false,
|
|
3145
|
+
queryModified: false
|
|
3146
|
+
},
|
|
3147
|
+
errors: []
|
|
2804
3148
|
};
|
|
2805
3149
|
} else if (classification.visualizations.length === 1) {
|
|
2806
3150
|
const vizType = classification.visualizations[0];
|
|
2807
3151
|
logCollector?.info(`Matching single component for type: ${vizType}`);
|
|
2808
3152
|
const result = await this.generateAnalyticalComponent(userPrompt, components, vizType, apiKey, logCollector, conversationHistory);
|
|
2809
3153
|
return {
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
3154
|
+
success: true,
|
|
3155
|
+
data: {
|
|
3156
|
+
component: result.component,
|
|
3157
|
+
reasoning: result.reasoning,
|
|
3158
|
+
method: "classification-generated",
|
|
3159
|
+
questionType: classification.questionType,
|
|
3160
|
+
needsMultipleComponents: false,
|
|
3161
|
+
propsModified: false,
|
|
3162
|
+
queryModified: false
|
|
3163
|
+
},
|
|
3164
|
+
errors: []
|
|
2817
3165
|
};
|
|
2818
3166
|
} else {
|
|
2819
3167
|
logCollector?.info("No specific visualization type - matching from all components");
|
|
2820
3168
|
const result = await this.generateAnalyticalComponent(userPrompt, components, void 0, apiKey, logCollector, conversationHistory);
|
|
2821
3169
|
return {
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
3170
|
+
success: true,
|
|
3171
|
+
data: {
|
|
3172
|
+
component: result.component,
|
|
3173
|
+
reasoning: result.reasoning,
|
|
3174
|
+
method: "classification-generated-auto",
|
|
3175
|
+
questionType: classification.questionType,
|
|
3176
|
+
needsMultipleComponents: false,
|
|
3177
|
+
propsModified: false,
|
|
3178
|
+
queryModified: false
|
|
3179
|
+
},
|
|
3180
|
+
errors: []
|
|
2829
3181
|
};
|
|
2830
3182
|
}
|
|
2831
3183
|
} else if (classification.questionType === "data_modification" || classification.questionType === "general") {
|
|
@@ -2833,28 +3185,109 @@ var BaseLLM = class {
|
|
|
2833
3185
|
logCollector?.info(matchMsg);
|
|
2834
3186
|
const matchResult = await this.matchComponent(userPrompt, components, apiKey, logCollector, conversationHistory);
|
|
2835
3187
|
return {
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
3188
|
+
success: true,
|
|
3189
|
+
data: {
|
|
3190
|
+
component: matchResult.component,
|
|
3191
|
+
reasoning: matchResult.reasoning,
|
|
3192
|
+
method: "classification-matched",
|
|
3193
|
+
questionType: classification.questionType,
|
|
3194
|
+
needsMultipleComponents: false,
|
|
3195
|
+
propsModified: matchResult.propsModified,
|
|
3196
|
+
queryModified: matchResult.queryModified
|
|
3197
|
+
},
|
|
3198
|
+
errors: []
|
|
2843
3199
|
};
|
|
2844
3200
|
} else {
|
|
2845
3201
|
logCollector?.info("General question - no component needed");
|
|
2846
3202
|
return {
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
3203
|
+
success: true,
|
|
3204
|
+
data: {
|
|
3205
|
+
component: null,
|
|
3206
|
+
reasoning: "General question - no component needed",
|
|
3207
|
+
method: "classification-general",
|
|
3208
|
+
questionType: classification.questionType,
|
|
3209
|
+
needsMultipleComponents: false,
|
|
3210
|
+
propsModified: false,
|
|
3211
|
+
queryModified: false
|
|
3212
|
+
},
|
|
3213
|
+
errors: []
|
|
2852
3214
|
};
|
|
2853
3215
|
}
|
|
2854
3216
|
} catch (error) {
|
|
2855
|
-
|
|
2856
|
-
|
|
3217
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3218
|
+
logger.error(`[${this.getProviderName()}] Error generating component response: ${errorMsg}`);
|
|
3219
|
+
logger.debug(`[${this.getProviderName()}] Component response generation error details:`, error);
|
|
3220
|
+
logCollector?.error(`Error generating component response: ${errorMsg}`);
|
|
3221
|
+
errors.push(errorMsg);
|
|
3222
|
+
return {
|
|
3223
|
+
success: false,
|
|
3224
|
+
errors,
|
|
3225
|
+
data: void 0
|
|
3226
|
+
};
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
/**
|
|
3230
|
+
* Main orchestration function that classifies question and routes to appropriate handler
|
|
3231
|
+
* This is the NEW recommended entry point for handling user requests
|
|
3232
|
+
* Supports both component generation and text response modes
|
|
3233
|
+
*
|
|
3234
|
+
* @param responseMode - 'component' for component generation (default), 'text' for text responses
|
|
3235
|
+
*/
|
|
3236
|
+
async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") {
|
|
3237
|
+
logger.info(`[${this.getProviderName()}] handleUserRequest called with responseMode: ${responseMode}`);
|
|
3238
|
+
if (responseMode === "text") {
|
|
3239
|
+
logger.info(`[${this.getProviderName()}] Using text response mode`);
|
|
3240
|
+
logCollector?.info("Generating text response...");
|
|
3241
|
+
const textResponse = await this.generateTextResponse(
|
|
3242
|
+
userPrompt,
|
|
3243
|
+
apiKey,
|
|
3244
|
+
logCollector,
|
|
3245
|
+
conversationHistory
|
|
3246
|
+
);
|
|
3247
|
+
if (!textResponse.success) {
|
|
3248
|
+
logger.error(`[${this.getProviderName()}] Text response generation failed`);
|
|
3249
|
+
return textResponse;
|
|
3250
|
+
}
|
|
3251
|
+
logger.info(`[${this.getProviderName()}] Text response generated successfully`);
|
|
3252
|
+
return {
|
|
3253
|
+
success: true,
|
|
3254
|
+
data: {
|
|
3255
|
+
textResponse: textResponse.data.text,
|
|
3256
|
+
text: textResponse.data.text,
|
|
3257
|
+
responseType: textResponse.data.responseType,
|
|
3258
|
+
confidence: textResponse.data.confidence,
|
|
3259
|
+
reasoning: textResponse.data.reasoning,
|
|
3260
|
+
method: `${this.getProviderName()}-text-response`
|
|
3261
|
+
},
|
|
3262
|
+
errors: []
|
|
3263
|
+
};
|
|
2857
3264
|
}
|
|
3265
|
+
const componentResponse = await this.generateComponentResponse(
|
|
3266
|
+
userPrompt,
|
|
3267
|
+
components,
|
|
3268
|
+
apiKey,
|
|
3269
|
+
logCollector,
|
|
3270
|
+
conversationHistory
|
|
3271
|
+
);
|
|
3272
|
+
if (!componentResponse.success) {
|
|
3273
|
+
logger.error(`[${this.getProviderName()}] Component response generation failed`);
|
|
3274
|
+
return componentResponse;
|
|
3275
|
+
}
|
|
3276
|
+
logger.info(`[${this.getProviderName()}] Component response generated successfully`);
|
|
3277
|
+
return {
|
|
3278
|
+
success: true,
|
|
3279
|
+
data: {
|
|
3280
|
+
component: componentResponse.data.component,
|
|
3281
|
+
reasoning: componentResponse.data.reasoning,
|
|
3282
|
+
method: componentResponse.data.method,
|
|
3283
|
+
// Preserve the original method name
|
|
3284
|
+
questionType: componentResponse.data.questionType,
|
|
3285
|
+
needsMultipleComponents: componentResponse.data.needsMultipleComponents,
|
|
3286
|
+
propsModified: componentResponse.data.propsModified,
|
|
3287
|
+
queryModified: componentResponse.data.queryModified
|
|
3288
|
+
},
|
|
3289
|
+
errors: []
|
|
3290
|
+
};
|
|
2858
3291
|
}
|
|
2859
3292
|
/**
|
|
2860
3293
|
* Generate next questions that the user might ask based on the original prompt and generated component
|
|
@@ -2900,8 +3333,10 @@ var BaseLLM = class {
|
|
|
2900
3333
|
);
|
|
2901
3334
|
return nextQuestions;
|
|
2902
3335
|
} catch (error) {
|
|
2903
|
-
|
|
2904
|
-
|
|
3336
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3337
|
+
logger.error(`[${this.getProviderName()}] Error generating next questions: ${errorMsg}`);
|
|
3338
|
+
logger.debug(`[${this.getProviderName()}] Next questions generation error details:`, error);
|
|
3339
|
+
logCollector?.error(`Error generating next questions: ${errorMsg}`);
|
|
2905
3340
|
return [];
|
|
2906
3341
|
}
|
|
2907
3342
|
}
|
|
@@ -2965,112 +3400,130 @@ function getLLMProviders() {
|
|
|
2965
3400
|
return DEFAULT_PROVIDERS;
|
|
2966
3401
|
}
|
|
2967
3402
|
}
|
|
2968
|
-
var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory) => {
|
|
2969
|
-
|
|
2970
|
-
|
|
3403
|
+
var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") => {
|
|
3404
|
+
logger.debug("[useAnthropicMethod] Initializing Anthropic Claude matching method");
|
|
3405
|
+
logger.debug(`[useAnthropicMethod] Response mode: ${responseMode}`);
|
|
3406
|
+
const msg = `Using Anthropic Claude ${responseMode === "text" ? "text response" : "matching"} method...`;
|
|
2971
3407
|
logCollector?.info(msg);
|
|
2972
|
-
if (components.length === 0) {
|
|
3408
|
+
if (responseMode === "component" && components.length === 0) {
|
|
2973
3409
|
const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
|
|
3410
|
+
logger.error("[useAnthropicMethod] No components available");
|
|
2974
3411
|
logCollector?.error(emptyMsg);
|
|
2975
|
-
return { success: false,
|
|
2976
|
-
}
|
|
2977
|
-
try {
|
|
2978
|
-
const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory);
|
|
2979
|
-
return { success: true, data: matchResult };
|
|
2980
|
-
} catch (error) {
|
|
2981
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2982
|
-
logCollector?.error(`Anthropic method failed: ${errorMsg}`);
|
|
2983
|
-
throw error;
|
|
3412
|
+
return { success: false, errors: [emptyMsg] };
|
|
2984
3413
|
}
|
|
3414
|
+
logger.debug(`[useAnthropicMethod] Processing with ${components.length} components`);
|
|
3415
|
+
const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode);
|
|
3416
|
+
logger.info(`[useAnthropicMethod] Successfully generated ${responseMode} using Anthropic`);
|
|
3417
|
+
return matchResult;
|
|
2985
3418
|
};
|
|
2986
|
-
var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory) => {
|
|
2987
|
-
|
|
2988
|
-
|
|
3419
|
+
var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") => {
|
|
3420
|
+
logger.debug("[useGroqMethod] Initializing Groq LLM matching method");
|
|
3421
|
+
logger.debug(`[useGroqMethod] Response mode: ${responseMode}`);
|
|
3422
|
+
const msg = `Using Groq LLM ${responseMode === "text" ? "text response" : "matching"} method...`;
|
|
3423
|
+
logger.info(msg);
|
|
2989
3424
|
logCollector?.info(msg);
|
|
2990
|
-
if (components.length === 0) {
|
|
3425
|
+
if (responseMode === "component" && components.length === 0) {
|
|
2991
3426
|
const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
|
|
3427
|
+
logger.error("[useGroqMethod] No components available");
|
|
2992
3428
|
logCollector?.error(emptyMsg);
|
|
2993
|
-
return { success: false,
|
|
2994
|
-
}
|
|
2995
|
-
try {
|
|
2996
|
-
const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory);
|
|
2997
|
-
return { success: true, data: matchResult };
|
|
2998
|
-
} catch (error) {
|
|
2999
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3000
|
-
logCollector?.error(`Groq method failed: ${errorMsg}`);
|
|
3001
|
-
throw error;
|
|
3429
|
+
return { success: false, errors: [emptyMsg] };
|
|
3002
3430
|
}
|
|
3431
|
+
logger.debug(`[useGroqMethod] Processing with ${components.length} components`);
|
|
3432
|
+
const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode);
|
|
3433
|
+
logger.info(`[useGroqMethod] Successfully generated ${responseMode} using Groq`);
|
|
3434
|
+
return matchResult;
|
|
3003
3435
|
};
|
|
3004
3436
|
var getUserResponseFromCache = async (prompt) => {
|
|
3005
3437
|
return false;
|
|
3006
3438
|
};
|
|
3007
3439
|
var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory) => {
|
|
3440
|
+
const responseMode = "component";
|
|
3441
|
+
logger.debug(`[get_user_response] Starting user response generation for prompt: "${prompt.substring(0, 50)}..."`);
|
|
3442
|
+
logger.debug("[get_user_response] Checking cache for existing response");
|
|
3008
3443
|
const userResponse = await getUserResponseFromCache(prompt);
|
|
3009
3444
|
if (userResponse) {
|
|
3445
|
+
logger.info("[get_user_response] User response found in cache - returning cached result");
|
|
3010
3446
|
logCollector?.info("User response found in cache");
|
|
3011
3447
|
return {
|
|
3012
3448
|
success: true,
|
|
3013
|
-
data: userResponse
|
|
3449
|
+
data: userResponse,
|
|
3450
|
+
errors: []
|
|
3014
3451
|
};
|
|
3015
3452
|
}
|
|
3453
|
+
logger.debug("[get_user_response] No cached response found, proceeding with LLM providers");
|
|
3016
3454
|
const providers = llmProviders || getLLMProviders();
|
|
3017
3455
|
const errors = [];
|
|
3018
3456
|
const providerOrder = providers.join(", ");
|
|
3019
3457
|
logCollector?.info(`LLM Provider order: [${providerOrder}]`);
|
|
3020
3458
|
if (conversationHistory && conversationHistory.length > 0) {
|
|
3021
|
-
|
|
3459
|
+
const exchangeCount = conversationHistory.split("\n").filter((l) => l.startsWith("Q")).length;
|
|
3460
|
+
logger.debug(`[get_user_response] Using conversation history with ${exchangeCount} previous exchanges`);
|
|
3461
|
+
logCollector?.info(`Using conversation history with ${exchangeCount} previous exchanges`);
|
|
3462
|
+
} else {
|
|
3463
|
+
logger.debug("[get_user_response] No conversation history available");
|
|
3022
3464
|
}
|
|
3023
3465
|
for (let i = 0; i < providers.length; i++) {
|
|
3024
3466
|
const provider = providers[i];
|
|
3025
3467
|
const isLastProvider = i === providers.length - 1;
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
}
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
const errorMsg = `Provider ${provider} failed: ${errorMessage}`;
|
|
3050
|
-
logCollector?.error(errorMsg);
|
|
3468
|
+
const attemptMsg = `Attempting provider: ${provider} (${i + 1}/${providers.length})`;
|
|
3469
|
+
logCollector?.info(attemptMsg);
|
|
3470
|
+
let result;
|
|
3471
|
+
if (provider === "anthropic") {
|
|
3472
|
+
result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory, responseMode);
|
|
3473
|
+
} else if (provider === "groq") {
|
|
3474
|
+
result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory, responseMode);
|
|
3475
|
+
} else {
|
|
3476
|
+
logger.warn(`[get_user_response] Unknown provider: ${provider} - skipping`);
|
|
3477
|
+
errors.push(`Unknown provider: ${provider}`);
|
|
3478
|
+
continue;
|
|
3479
|
+
}
|
|
3480
|
+
if (result.success) {
|
|
3481
|
+
const successMsg = `Success with provider: ${provider} result: ${JSON.stringify(result)}`;
|
|
3482
|
+
logger.info(`${successMsg}`);
|
|
3483
|
+
logCollector?.info(successMsg);
|
|
3484
|
+
return result;
|
|
3485
|
+
} else {
|
|
3486
|
+
const providerErrors = result.errors.map((err) => `${provider}: ${err}`);
|
|
3487
|
+
errors.push(...providerErrors);
|
|
3488
|
+
const warnMsg = `Provider ${provider} returned unsuccessful result: ${result.errors.join(", ")}`;
|
|
3489
|
+
logger.warn(`[get_user_response] ${warnMsg}`);
|
|
3490
|
+
logCollector?.warn(warnMsg);
|
|
3051
3491
|
if (!isLastProvider) {
|
|
3052
3492
|
const fallbackMsg = "Falling back to next provider...";
|
|
3493
|
+
logger.info(`[get_user_response] ${fallbackMsg}`);
|
|
3053
3494
|
logCollector?.info(fallbackMsg);
|
|
3054
|
-
continue;
|
|
3055
3495
|
}
|
|
3056
3496
|
}
|
|
3057
3497
|
}
|
|
3058
|
-
const
|
|
3059
|
-
|
|
3060
|
-
logCollector?.error(failureMsg);
|
|
3498
|
+
const failureMsg = `All LLM providers failed`;
|
|
3499
|
+
logger.error(`[get_user_response] ${failureMsg}. Errors: ${errors.join("; ")}`);
|
|
3500
|
+
logCollector?.error(`${failureMsg}. Errors: ${errors.join("; ")}`);
|
|
3061
3501
|
return {
|
|
3062
3502
|
success: false,
|
|
3063
|
-
|
|
3503
|
+
errors
|
|
3064
3504
|
};
|
|
3065
3505
|
};
|
|
3066
3506
|
|
|
3067
3507
|
// src/utils/log-collector.ts
|
|
3508
|
+
var LOG_LEVEL_PRIORITY2 = {
|
|
3509
|
+
errors: 0,
|
|
3510
|
+
warnings: 1,
|
|
3511
|
+
info: 2,
|
|
3512
|
+
verbose: 3
|
|
3513
|
+
};
|
|
3514
|
+
var MESSAGE_LEVEL_PRIORITY2 = {
|
|
3515
|
+
error: 0,
|
|
3516
|
+
warn: 1,
|
|
3517
|
+
info: 2,
|
|
3518
|
+
debug: 3
|
|
3519
|
+
};
|
|
3068
3520
|
var UILogCollector = class {
|
|
3069
3521
|
constructor(clientId, sendMessage, uiBlockId) {
|
|
3070
3522
|
this.logs = [];
|
|
3071
3523
|
this.uiBlockId = uiBlockId || null;
|
|
3072
3524
|
this.clientId = clientId;
|
|
3073
3525
|
this.sendMessage = sendMessage;
|
|
3526
|
+
this.currentLogLevel = logger.getLogLevel();
|
|
3074
3527
|
}
|
|
3075
3528
|
/**
|
|
3076
3529
|
* Check if logging is enabled (uiBlockId is provided)
|
|
@@ -3078,10 +3531,22 @@ var UILogCollector = class {
|
|
|
3078
3531
|
isEnabled() {
|
|
3079
3532
|
return this.uiBlockId !== null;
|
|
3080
3533
|
}
|
|
3534
|
+
/**
|
|
3535
|
+
* Check if a message should be logged based on current log level
|
|
3536
|
+
*/
|
|
3537
|
+
shouldLog(messageLevel) {
|
|
3538
|
+
const currentLevelPriority = LOG_LEVEL_PRIORITY2[this.currentLogLevel];
|
|
3539
|
+
const messagePriority = MESSAGE_LEVEL_PRIORITY2[messageLevel];
|
|
3540
|
+
return messagePriority <= currentLevelPriority;
|
|
3541
|
+
}
|
|
3081
3542
|
/**
|
|
3082
3543
|
* Add a log entry with timestamp and immediately send to runtime
|
|
3544
|
+
* Only logs that pass the log level filter are captured and sent
|
|
3083
3545
|
*/
|
|
3084
3546
|
addLog(level, message, type, data) {
|
|
3547
|
+
if (!this.shouldLog(level)) {
|
|
3548
|
+
return;
|
|
3549
|
+
}
|
|
3085
3550
|
const log = {
|
|
3086
3551
|
timestamp: Date.now(),
|
|
3087
3552
|
level,
|
|
@@ -3091,7 +3556,20 @@ var UILogCollector = class {
|
|
|
3091
3556
|
};
|
|
3092
3557
|
this.logs.push(log);
|
|
3093
3558
|
this.sendLogImmediately(log);
|
|
3094
|
-
|
|
3559
|
+
switch (level) {
|
|
3560
|
+
case "error":
|
|
3561
|
+
logger.error("UILogCollector:", log);
|
|
3562
|
+
break;
|
|
3563
|
+
case "warn":
|
|
3564
|
+
logger.warn("UILogCollector:", log);
|
|
3565
|
+
break;
|
|
3566
|
+
case "info":
|
|
3567
|
+
logger.info("UILogCollector:", log);
|
|
3568
|
+
break;
|
|
3569
|
+
case "debug":
|
|
3570
|
+
logger.debug("UILogCollector:", log);
|
|
3571
|
+
break;
|
|
3572
|
+
}
|
|
3095
3573
|
}
|
|
3096
3574
|
/**
|
|
3097
3575
|
* Send a single log to runtime immediately
|
|
@@ -3222,102 +3700,131 @@ var CONTEXT_CONFIG = {
|
|
|
3222
3700
|
|
|
3223
3701
|
// src/handlers/user-prompt-request.ts
|
|
3224
3702
|
var processedMessageIds = /* @__PURE__ */ new Set();
|
|
3225
|
-
async
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
const
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3703
|
+
var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders) => {
|
|
3704
|
+
const errors = [];
|
|
3705
|
+
logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
|
|
3706
|
+
const parseResult = UserPromptRequestMessageSchema.safeParse(data);
|
|
3707
|
+
if (!parseResult.success) {
|
|
3708
|
+
const zodError = parseResult.error;
|
|
3709
|
+
zodError.errors.forEach((err) => {
|
|
3710
|
+
errors.push(`${err.path.join(".")}: ${err.message}`);
|
|
3711
|
+
});
|
|
3712
|
+
return { success: false, errors };
|
|
3713
|
+
}
|
|
3714
|
+
const userPromptRequest = parseResult.data;
|
|
3715
|
+
const { id, payload } = userPromptRequest;
|
|
3716
|
+
const prompt = payload.prompt;
|
|
3717
|
+
const SA_RUNTIME = payload.SA_RUNTIME;
|
|
3718
|
+
const wsId = userPromptRequest.from.id || "unknown";
|
|
3719
|
+
logger.debug(`[REQUEST ${id}] Full request details - wsId: ${wsId}, prompt length: ${prompt.length}`);
|
|
3720
|
+
if (processedMessageIds.has(id)) {
|
|
3721
|
+
logger.warn(`[REQUEST ${id}] Duplicate request detected - ignoring`);
|
|
3722
|
+
}
|
|
3723
|
+
processedMessageIds.add(id);
|
|
3724
|
+
logger.debug(`[REQUEST ${id}] Message ID marked as processed (${processedMessageIds.size} total)`);
|
|
3725
|
+
if (processedMessageIds.size > 100) {
|
|
3726
|
+
const firstId = processedMessageIds.values().next().value;
|
|
3727
|
+
if (firstId) {
|
|
3728
|
+
processedMessageIds.delete(firstId);
|
|
3729
|
+
logger.debug(`[REQUEST ${id}] Cleaned up old message ID from cache`);
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
if (!SA_RUNTIME) {
|
|
3733
|
+
errors.push("SA_RUNTIME is required");
|
|
3734
|
+
}
|
|
3735
|
+
const threadId = SA_RUNTIME?.threadId;
|
|
3736
|
+
const existingUiBlockId = SA_RUNTIME?.uiBlockId;
|
|
3737
|
+
if (!threadId) {
|
|
3738
|
+
errors.push("threadId in SA_RUNTIME is required");
|
|
3739
|
+
}
|
|
3740
|
+
if (!existingUiBlockId) {
|
|
3741
|
+
errors.push("uiBlockId in SA_RUNTIME is required");
|
|
3742
|
+
}
|
|
3743
|
+
if (!prompt) {
|
|
3744
|
+
errors.push("Prompt not found");
|
|
3745
|
+
}
|
|
3746
|
+
if (!components || components.length === 0) {
|
|
3747
|
+
errors.push("Components not found");
|
|
3748
|
+
}
|
|
3749
|
+
if (errors.length > 0) {
|
|
3750
|
+
return { success: false, errors, id, wsId };
|
|
3751
|
+
}
|
|
3752
|
+
const logCollector = new UILogCollector(wsId, sendMessage, existingUiBlockId);
|
|
3753
|
+
const threadManager = ThreadManager.getInstance();
|
|
3754
|
+
let thread = threadManager.getThread(threadId);
|
|
3755
|
+
if (!thread) {
|
|
3756
|
+
thread = threadManager.createThread(threadId);
|
|
3757
|
+
logger.info(`Created new thread: ${threadId}`);
|
|
3758
|
+
}
|
|
3759
|
+
logCollector.info(`Starting user prompt request with ${components.length} components`);
|
|
3760
|
+
const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
|
|
3761
|
+
logger.info("conversationHistory", conversationHistory);
|
|
3762
|
+
const userResponse = await get_user_response(prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory);
|
|
3763
|
+
logger.info("llm userResponse", userResponse);
|
|
3764
|
+
logCollector.info("User prompt request completed");
|
|
3765
|
+
const uiBlockId = existingUiBlockId;
|
|
3766
|
+
if (!userResponse.success) {
|
|
3767
|
+
logger.error(`User prompt request failed with errors: ${userResponse.errors.join(", ")}`);
|
|
3768
|
+
return {
|
|
3769
|
+
success: false,
|
|
3770
|
+
data: userResponse.data,
|
|
3771
|
+
errors: userResponse.errors,
|
|
3772
|
+
uiBlockId,
|
|
3773
|
+
threadId,
|
|
3774
|
+
id,
|
|
3775
|
+
wsId
|
|
3776
|
+
};
|
|
3777
|
+
}
|
|
3778
|
+
let component = null;
|
|
3779
|
+
let textResponse = null;
|
|
3780
|
+
if (userResponse.data) {
|
|
3781
|
+
if (typeof userResponse.data === "object") {
|
|
3782
|
+
if ("component" in userResponse.data) {
|
|
3783
|
+
component = userResponse.data.component;
|
|
3784
|
+
}
|
|
3785
|
+
if ("textResponse" in userResponse.data) {
|
|
3786
|
+
textResponse = userResponse.data.textResponse;
|
|
3242
3787
|
}
|
|
3243
3788
|
}
|
|
3244
|
-
if (!SA_RUNTIME) {
|
|
3245
|
-
sendDataResponse4(id, {
|
|
3246
|
-
success: false,
|
|
3247
|
-
error: "SA_RUNTIME is required"
|
|
3248
|
-
}, sendMessage, wsId);
|
|
3249
|
-
return;
|
|
3250
|
-
}
|
|
3251
|
-
const threadId = SA_RUNTIME.threadId;
|
|
3252
|
-
const existingUiBlockId = SA_RUNTIME.uiBlockId;
|
|
3253
|
-
if (!threadId) {
|
|
3254
|
-
sendDataResponse4(id, {
|
|
3255
|
-
success: false,
|
|
3256
|
-
error: "threadId in SA_RUNTIME is required"
|
|
3257
|
-
}, sendMessage, wsId);
|
|
3258
|
-
return;
|
|
3259
|
-
}
|
|
3260
|
-
if (!existingUiBlockId) {
|
|
3261
|
-
sendDataResponse4(id, {
|
|
3262
|
-
success: false,
|
|
3263
|
-
error: "uiBlockId in SA_RUNTIME is required"
|
|
3264
|
-
}, sendMessage, wsId);
|
|
3265
|
-
return;
|
|
3266
|
-
}
|
|
3267
|
-
const logCollector = new UILogCollector(wsId, sendMessage, existingUiBlockId);
|
|
3268
|
-
if (!prompt) {
|
|
3269
|
-
sendDataResponse4(id, {
|
|
3270
|
-
success: false,
|
|
3271
|
-
error: "Prompt not found"
|
|
3272
|
-
}, sendMessage, wsId);
|
|
3273
|
-
return;
|
|
3274
|
-
}
|
|
3275
|
-
if (!components || components.length === 0) {
|
|
3276
|
-
sendDataResponse4(id, {
|
|
3277
|
-
success: false,
|
|
3278
|
-
error: "Components not found"
|
|
3279
|
-
}, sendMessage, wsId);
|
|
3280
|
-
return;
|
|
3281
|
-
}
|
|
3282
|
-
const threadManager = ThreadManager.getInstance();
|
|
3283
|
-
let thread = threadManager.getThread(threadId);
|
|
3284
|
-
if (!thread) {
|
|
3285
|
-
thread = threadManager.createThread(threadId);
|
|
3286
|
-
logger.info(`Created new thread: ${threadId}`);
|
|
3287
|
-
}
|
|
3288
|
-
logCollector.info(`Starting user prompt request with ${components.length} components`);
|
|
3289
|
-
const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
|
|
3290
|
-
logger.info("conversationHistory", conversationHistory);
|
|
3291
|
-
const userResponse = await get_user_response(prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory);
|
|
3292
|
-
logger.info("llm userResponse", userResponse);
|
|
3293
|
-
logCollector.info("User prompt request completed");
|
|
3294
|
-
if (userResponse.success && userResponse.data && typeof userResponse.data === "object" && "component" in userResponse.data) {
|
|
3295
|
-
const component = userResponse.data.component;
|
|
3296
|
-
const uiBlockId = existingUiBlockId;
|
|
3297
|
-
const uiBlock = new UIBlock(
|
|
3298
|
-
prompt,
|
|
3299
|
-
{},
|
|
3300
|
-
// componentData: initially empty, will be filled later
|
|
3301
|
-
component || {},
|
|
3302
|
-
// generatedComponentMetadata: full component object (ComponentSchema)
|
|
3303
|
-
[],
|
|
3304
|
-
// actions: empty initially
|
|
3305
|
-
uiBlockId
|
|
3306
|
-
);
|
|
3307
|
-
thread.addUIBlock(uiBlock);
|
|
3308
|
-
logger.info(`Created UIBlock: ${uiBlockId} in Thread: ${threadId}`);
|
|
3309
|
-
sendDataResponse4(id, {
|
|
3310
|
-
...userResponse,
|
|
3311
|
-
uiBlockId,
|
|
3312
|
-
threadId
|
|
3313
|
-
}, sendMessage, wsId);
|
|
3314
|
-
} else {
|
|
3315
|
-
sendDataResponse4(id, userResponse, sendMessage, wsId);
|
|
3316
|
-
}
|
|
3317
|
-
return;
|
|
3318
|
-
} catch (error) {
|
|
3319
|
-
logger.error("Failed to handle user prompt request:", error);
|
|
3320
3789
|
}
|
|
3790
|
+
const uiBlock = new UIBlock(
|
|
3791
|
+
prompt,
|
|
3792
|
+
{},
|
|
3793
|
+
// componentData: initially empty, will be filled later
|
|
3794
|
+
component,
|
|
3795
|
+
// generatedComponentMetadata: full component object (ComponentSchema)
|
|
3796
|
+
[],
|
|
3797
|
+
// actions: empty initially
|
|
3798
|
+
uiBlockId,
|
|
3799
|
+
textResponse
|
|
3800
|
+
// textResponse: text response from LLM
|
|
3801
|
+
);
|
|
3802
|
+
thread.addUIBlock(uiBlock);
|
|
3803
|
+
logger.info(`Created UIBlock: ${uiBlockId} in Thread: ${threadId}`);
|
|
3804
|
+
return {
|
|
3805
|
+
success: userResponse.success,
|
|
3806
|
+
data: userResponse.data,
|
|
3807
|
+
errors: userResponse.errors,
|
|
3808
|
+
uiBlockId,
|
|
3809
|
+
threadId,
|
|
3810
|
+
id,
|
|
3811
|
+
wsId
|
|
3812
|
+
};
|
|
3813
|
+
};
|
|
3814
|
+
async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders) {
|
|
3815
|
+
const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders);
|
|
3816
|
+
sendDataResponse4(
|
|
3817
|
+
response.id || data.id,
|
|
3818
|
+
{
|
|
3819
|
+
success: response.success,
|
|
3820
|
+
errors: response.errors,
|
|
3821
|
+
data: response.data,
|
|
3822
|
+
uiBlockId: response.uiBlockId,
|
|
3823
|
+
threadId: response.threadId
|
|
3824
|
+
},
|
|
3825
|
+
sendMessage,
|
|
3826
|
+
response.wsId || data.from?.id
|
|
3827
|
+
);
|
|
3321
3828
|
}
|
|
3322
3829
|
function sendDataResponse4(id, res, sendMessage, clientId) {
|
|
3323
3830
|
const response = {
|
|
@@ -3430,12 +3937,27 @@ function sendResponse(id, res, sendMessage, clientId) {
|
|
|
3430
3937
|
// src/userResponse/next-questions.ts
|
|
3431
3938
|
async function generateNextQuestions(originalUserPrompt, component, componentData, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory) {
|
|
3432
3939
|
try {
|
|
3940
|
+
logger.debug("[generateNextQuestions] Starting next questions generation");
|
|
3941
|
+
logger.debug(`[generateNextQuestions] User prompt: "${originalUserPrompt?.substring(0, 50)}..."`);
|
|
3942
|
+
logger.debug(`[generateNextQuestions] Component: ${component?.name || "unknown"} (${component?.type || "unknown"})`);
|
|
3943
|
+
logger.debug(`[generateNextQuestions] Component data available: ${componentData ? "yes" : "no"}`);
|
|
3433
3944
|
const providers = llmProviders || ["anthropic"];
|
|
3434
|
-
|
|
3945
|
+
logger.info(`[generateNextQuestions] Using LLM providers: [${providers.join(", ")}]`);
|
|
3946
|
+
if (conversationHistory && conversationHistory.length > 0) {
|
|
3947
|
+
const exchangeCount = conversationHistory.split("\n").filter((l) => l.startsWith("Q")).length;
|
|
3948
|
+
logger.debug(`[generateNextQuestions] Using conversation history with ${exchangeCount} previous exchanges`);
|
|
3949
|
+
} else {
|
|
3950
|
+
logger.debug("[generateNextQuestions] No conversation history available");
|
|
3951
|
+
}
|
|
3952
|
+
for (let i = 0; i < providers.length; i++) {
|
|
3953
|
+
const provider = providers[i];
|
|
3954
|
+
const isLastProvider = i === providers.length - 1;
|
|
3435
3955
|
try {
|
|
3436
|
-
logger.info(`
|
|
3956
|
+
logger.info(`[generateNextQuestions] Attempting provider: ${provider} (${i + 1}/${providers.length})`);
|
|
3957
|
+
logCollector?.info(`Generating questions with ${provider}...`);
|
|
3437
3958
|
let result = [];
|
|
3438
3959
|
if (provider === "groq") {
|
|
3960
|
+
logger.debug("[generateNextQuestions] Using Groq LLM for next questions");
|
|
3439
3961
|
result = await groqLLM.generateNextQuestions(
|
|
3440
3962
|
originalUserPrompt,
|
|
3441
3963
|
component,
|
|
@@ -3445,6 +3967,7 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
|
|
|
3445
3967
|
conversationHistory
|
|
3446
3968
|
);
|
|
3447
3969
|
} else {
|
|
3970
|
+
logger.debug("[generateNextQuestions] Using Anthropic LLM for next questions");
|
|
3448
3971
|
result = await anthropicLLM.generateNextQuestions(
|
|
3449
3972
|
originalUserPrompt,
|
|
3450
3973
|
component,
|
|
@@ -3455,21 +3978,39 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
|
|
|
3455
3978
|
);
|
|
3456
3979
|
}
|
|
3457
3980
|
if (result && result.length > 0) {
|
|
3458
|
-
logger.info(`Successfully generated ${result.length} questions with ${provider}`);
|
|
3981
|
+
logger.info(`[generateNextQuestions] Successfully generated ${result.length} questions with ${provider}`);
|
|
3982
|
+
logger.debug(`[generateNextQuestions] Questions: ${JSON.stringify(result)}`);
|
|
3983
|
+
logCollector?.info(`Generated ${result.length} follow-up questions`);
|
|
3459
3984
|
return result;
|
|
3460
3985
|
}
|
|
3461
|
-
|
|
3986
|
+
const warnMsg = `No questions generated from ${provider}${!isLastProvider ? ", trying next provider..." : ""}`;
|
|
3987
|
+
logger.warn(`[generateNextQuestions] ${warnMsg}`);
|
|
3988
|
+
if (!isLastProvider) {
|
|
3989
|
+
logCollector?.warn(warnMsg);
|
|
3990
|
+
}
|
|
3462
3991
|
} catch (providerError) {
|
|
3463
|
-
|
|
3464
|
-
|
|
3992
|
+
const errorMsg = providerError instanceof Error ? providerError.message : String(providerError);
|
|
3993
|
+
logger.error(`[generateNextQuestions] Provider ${provider} failed: ${errorMsg}`);
|
|
3994
|
+
logger.debug(`[generateNextQuestions] Provider error details:`, providerError);
|
|
3995
|
+
if (!isLastProvider) {
|
|
3996
|
+
const fallbackMsg = `Provider ${provider} failed, trying next provider...`;
|
|
3997
|
+
logger.info(`[generateNextQuestions] ${fallbackMsg}`);
|
|
3998
|
+
logCollector?.warn(fallbackMsg);
|
|
3999
|
+
} else {
|
|
4000
|
+
logCollector?.error(`Failed to generate questions with ${provider}`);
|
|
4001
|
+
}
|
|
3465
4002
|
continue;
|
|
3466
4003
|
}
|
|
3467
4004
|
}
|
|
3468
|
-
logger.warn("All providers failed or returned no questions");
|
|
4005
|
+
logger.warn("[generateNextQuestions] All providers failed or returned no questions");
|
|
4006
|
+
logCollector?.warn("Unable to generate follow-up questions");
|
|
3469
4007
|
return [];
|
|
3470
4008
|
} catch (error) {
|
|
3471
|
-
|
|
3472
|
-
|
|
4009
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
4010
|
+
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
4011
|
+
logger.error(`[generateNextQuestions] Error generating next questions: ${errorMsg}`);
|
|
4012
|
+
logger.debug("[generateNextQuestions] Error stack trace:", errorStack);
|
|
4013
|
+
logCollector?.error(`Error generating next questions: ${errorMsg}`);
|
|
3473
4014
|
return [];
|
|
3474
4015
|
}
|
|
3475
4016
|
}
|
|
@@ -3477,11 +4018,15 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
|
|
|
3477
4018
|
// src/handlers/actions-request.ts
|
|
3478
4019
|
async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiKey, llmProviders) {
|
|
3479
4020
|
try {
|
|
4021
|
+
logger.debug("[ACTIONS_REQ] Parsing incoming actions request");
|
|
3480
4022
|
const actionsRequest = ActionsRequestMessageSchema.parse(data);
|
|
3481
4023
|
const { id, payload } = actionsRequest;
|
|
3482
4024
|
const { SA_RUNTIME } = payload;
|
|
3483
4025
|
const wsId = actionsRequest.from.id || "unknown";
|
|
4026
|
+
logger.info(`[ACTIONS_REQ ${id}] Processing actions request from client: ${wsId}`);
|
|
4027
|
+
logger.debug(`[ACTIONS_REQ ${id}] Request payload:`, JSON.stringify(payload, null, 2).substring(0, 200));
|
|
3484
4028
|
if (!SA_RUNTIME) {
|
|
4029
|
+
logger.error(`[ACTIONS_REQ ${id}] SA_RUNTIME missing from request`);
|
|
3485
4030
|
sendResponse2(id, {
|
|
3486
4031
|
success: false,
|
|
3487
4032
|
error: "SA_RUNTIME with threadId and uiBlockId is required"
|
|
@@ -3490,31 +4035,54 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
|
|
|
3490
4035
|
}
|
|
3491
4036
|
const uiBlockId = SA_RUNTIME.uiBlockId;
|
|
3492
4037
|
const threadId = SA_RUNTIME.threadId;
|
|
4038
|
+
logger.debug(`[ACTIONS_REQ ${id}] SA_RUNTIME validated - threadId: ${threadId}, uiBlockId: ${uiBlockId}`);
|
|
4039
|
+
logger.debug(`[ACTIONS_REQ ${id}] Retrieving thread: ${threadId}`);
|
|
3493
4040
|
const threadManager = ThreadManager.getInstance();
|
|
3494
4041
|
const thread = threadManager.getThread(threadId);
|
|
3495
4042
|
if (!thread) {
|
|
4043
|
+
logger.error(`[ACTIONS_REQ ${id}] Thread '${threadId}' not found`);
|
|
3496
4044
|
sendResponse2(id, {
|
|
3497
4045
|
success: false,
|
|
3498
4046
|
error: `Thread '${threadId}' not found`
|
|
3499
4047
|
}, sendMessage, wsId);
|
|
3500
4048
|
return;
|
|
3501
4049
|
}
|
|
4050
|
+
logger.debug(`[ACTIONS_REQ ${id}] Thread found with ${thread.getUIBlocks().length} UIBlocks`);
|
|
4051
|
+
logger.debug(`[ACTIONS_REQ ${id}] Retrieving UIBlock: ${uiBlockId}`);
|
|
3502
4052
|
const uiBlock = thread.getUIBlock(uiBlockId);
|
|
3503
4053
|
if (!uiBlock) {
|
|
4054
|
+
logger.error(`[ACTIONS_REQ ${id}] UIBlock '${uiBlockId}' not found in thread '${threadId}'`);
|
|
3504
4055
|
sendResponse2(id, {
|
|
3505
4056
|
success: false,
|
|
3506
4057
|
error: `UIBlock '${uiBlockId}' not found in thread '${threadId}'`
|
|
3507
4058
|
}, sendMessage, wsId);
|
|
3508
4059
|
return;
|
|
3509
4060
|
}
|
|
4061
|
+
logger.info(`[ACTIONS_REQ ${id}] UIBlock retrieved successfully`);
|
|
4062
|
+
logger.debug(`[ACTIONS_REQ ${id}] Creating UILogCollector for uiBlockId: ${uiBlockId}`);
|
|
3510
4063
|
const logCollector = new UILogCollector(wsId, sendMessage, uiBlockId);
|
|
4064
|
+
logger.info(`[ACTIONS_REQ ${id}] UILogCollector initialized`);
|
|
4065
|
+
logger.debug(`[ACTIONS_REQ ${id}] Extracting data from UIBlock`);
|
|
3511
4066
|
const userQuestion = uiBlock.getUserQuestion();
|
|
3512
4067
|
const component = uiBlock.getComponentMetadata();
|
|
3513
4068
|
const componentData = uiBlock.getComponentData();
|
|
4069
|
+
logger.debug(`[ACTIONS_REQ ${id}] User question: "${userQuestion?.substring(0, 50)}..."`);
|
|
4070
|
+
logger.debug(`[ACTIONS_REQ ${id}] Component: ${component?.name || "unknown"} (${component?.type || "unknown"})`);
|
|
4071
|
+
logger.debug(`[ACTIONS_REQ ${id}] Component data available: ${componentData ? "yes" : "no"}`);
|
|
4072
|
+
logger.debug(`[ACTIONS_REQ ${id}] Extracting conversation history (max ${CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS} blocks)`);
|
|
3514
4073
|
const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, uiBlockId);
|
|
4074
|
+
const historyLineCount = conversationHistory.split("\n").filter((l) => l.trim()).length;
|
|
4075
|
+
logger.info(`[ACTIONS_REQ ${id}] Conversation history extracted: ${historyLineCount} lines`);
|
|
4076
|
+
logger.debug(`[ACTIONS_REQ ${id}] Conversation history preview:
|
|
4077
|
+
${conversationHistory.substring(0, 200)}...`);
|
|
3515
4078
|
logCollector.info(`Generating actions for UIBlock: ${uiBlockId}`);
|
|
3516
|
-
logger.info(`Generating actions for component: ${component?.name || "unknown"}`);
|
|
4079
|
+
logger.info(`[ACTIONS_REQ ${id}] Generating actions for component: ${component?.name || "unknown"}`);
|
|
4080
|
+
logger.debug(`[ACTIONS_REQ ${id}] Checking if actions are already cached`);
|
|
4081
|
+
const startTime = Date.now();
|
|
3517
4082
|
const actions = await uiBlock.getOrFetchActions(async () => {
|
|
4083
|
+
logger.info(`[ACTIONS_REQ ${id}] Actions not cached, generating new actions...`);
|
|
4084
|
+
logCollector.info("Generating follow-up questions...");
|
|
4085
|
+
logger.info(`[ACTIONS_REQ ${id}] Starting next questions generation with ${llmProviders?.join(", ") || "default"} providers`);
|
|
3518
4086
|
const nextQuestions = await generateNextQuestions(
|
|
3519
4087
|
userQuestion,
|
|
3520
4088
|
component,
|
|
@@ -3525,14 +4093,28 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
|
|
|
3525
4093
|
logCollector,
|
|
3526
4094
|
conversationHistory
|
|
3527
4095
|
);
|
|
3528
|
-
|
|
4096
|
+
logger.info(`[ACTIONS_REQ ${id}] Generated ${nextQuestions.length} questions`);
|
|
4097
|
+
logger.debug(`[ACTIONS_REQ ${id}] Questions: ${JSON.stringify(nextQuestions)}`);
|
|
4098
|
+
logger.debug(`[ACTIONS_REQ ${id}] Converting questions to actions format`);
|
|
4099
|
+
const convertedActions = nextQuestions.map((question, index) => ({
|
|
3529
4100
|
id: `action_${index}_${Date.now()}`,
|
|
3530
4101
|
name: question,
|
|
3531
4102
|
type: "next_question",
|
|
3532
4103
|
question
|
|
3533
4104
|
}));
|
|
4105
|
+
logger.debug(`[ACTIONS_REQ ${id}] Converted ${convertedActions.length} actions`);
|
|
4106
|
+
return convertedActions;
|
|
3534
4107
|
});
|
|
3535
|
-
|
|
4108
|
+
const processingTime = Date.now() - startTime;
|
|
4109
|
+
logger.info(`[ACTIONS_REQ ${id}] Actions retrieved in ${processingTime}ms - ${actions.length} actions total`);
|
|
4110
|
+
if (actions.length > 0) {
|
|
4111
|
+
logCollector.info(`Generated ${actions.length} follow-up questions successfully`);
|
|
4112
|
+
logger.debug(`[ACTIONS_REQ ${id}] Actions: ${actions.map((a) => a.name).join(", ")}`);
|
|
4113
|
+
} else {
|
|
4114
|
+
logger.warn(`[ACTIONS_REQ ${id}] No actions generated`);
|
|
4115
|
+
logCollector.warn("No follow-up questions could be generated");
|
|
4116
|
+
}
|
|
4117
|
+
logger.debug(`[ACTIONS_REQ ${id}] Sending successful response to client`);
|
|
3536
4118
|
sendResponse2(id, {
|
|
3537
4119
|
success: true,
|
|
3538
4120
|
data: {
|
|
@@ -3543,12 +4125,26 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
|
|
|
3543
4125
|
threadId
|
|
3544
4126
|
}
|
|
3545
4127
|
}, sendMessage, wsId);
|
|
4128
|
+
logger.info(`[ACTIONS_REQ ${id}] \u2713 Actions request completed successfully`);
|
|
3546
4129
|
} catch (error) {
|
|
3547
|
-
|
|
4130
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
4131
|
+
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
4132
|
+
logger.error(`[ACTIONS_REQ] Failed to handle actions request: ${errorMessage}`);
|
|
4133
|
+
logger.debug(`[ACTIONS_REQ] Error stack trace:`, errorStack);
|
|
4134
|
+
try {
|
|
4135
|
+
const parsedData = data;
|
|
4136
|
+
if (parsedData?.id && parsedData?.from?.id) {
|
|
4137
|
+
const logCollector = parsedData?.payload?.SA_RUNTIME?.uiBlockId ? new UILogCollector(parsedData.from.id, sendMessage, parsedData.payload.SA_RUNTIME.uiBlockId) : void 0;
|
|
4138
|
+
logCollector?.error(`Failed to generate actions: ${errorMessage}`);
|
|
4139
|
+
}
|
|
4140
|
+
} catch (logError) {
|
|
4141
|
+
logger.debug("[ACTIONS_REQ] Failed to send error logs to UI:", logError);
|
|
4142
|
+
}
|
|
3548
4143
|
sendResponse2(null, {
|
|
3549
4144
|
success: false,
|
|
3550
|
-
error:
|
|
4145
|
+
error: errorMessage
|
|
3551
4146
|
}, sendMessage);
|
|
4147
|
+
logger.info("[ACTIONS_REQ] \u2717 Actions request completed with errors");
|
|
3552
4148
|
}
|
|
3553
4149
|
}
|
|
3554
4150
|
function sendResponse2(id, res, sendMessage, clientId) {
|
|
@@ -3564,6 +4160,11 @@ function sendResponse2(id, res, sendMessage, clientId) {
|
|
|
3564
4160
|
...res
|
|
3565
4161
|
}
|
|
3566
4162
|
};
|
|
4163
|
+
logger.debug(`[ACTIONS_RES ${id || "unknown"}] Sending ${res.success ? "successful" : "failed"} response to client`);
|
|
4164
|
+
logger.debug(`[ACTIONS_RES ${id || "unknown"}] Response payload size: ${JSON.stringify(response).length} bytes`);
|
|
4165
|
+
if (res.data?.actions) {
|
|
4166
|
+
logger.debug(`[ACTIONS_RES ${id || "unknown"}] Sending ${res.data.actions.length} actions`);
|
|
4167
|
+
}
|
|
3567
4168
|
sendMessage(response);
|
|
3568
4169
|
}
|
|
3569
4170
|
|
|
@@ -3592,7 +4193,10 @@ async function handleUsersRequest(data, sendMessage) {
|
|
|
3592
4193
|
const { id, payload, from } = request;
|
|
3593
4194
|
const { operation, data: requestData } = payload;
|
|
3594
4195
|
const username = requestData?.username;
|
|
4196
|
+
const email = requestData?.email;
|
|
3595
4197
|
const password = requestData?.password;
|
|
4198
|
+
const fullname = requestData?.fullname;
|
|
4199
|
+
const role = requestData?.role;
|
|
3596
4200
|
if (from.type !== "admin") {
|
|
3597
4201
|
sendResponse3(id, {
|
|
3598
4202
|
success: false,
|
|
@@ -3604,10 +4208,10 @@ async function handleUsersRequest(data, sendMessage) {
|
|
|
3604
4208
|
const userManager = getUserManager();
|
|
3605
4209
|
switch (operation) {
|
|
3606
4210
|
case "create":
|
|
3607
|
-
await handleCreate(id, username, password, userManager, sendMessage, from.id);
|
|
4211
|
+
await handleCreate(id, { username, email, password, fullname, role }, userManager, sendMessage, from.id);
|
|
3608
4212
|
break;
|
|
3609
4213
|
case "update":
|
|
3610
|
-
await handleUpdate(id, username, password, userManager, sendMessage, from.id);
|
|
4214
|
+
await handleUpdate(id, { username, email, password, fullname, role }, userManager, sendMessage, from.id);
|
|
3611
4215
|
break;
|
|
3612
4216
|
case "delete":
|
|
3613
4217
|
await handleDelete(id, username, userManager, sendMessage, from.id);
|
|
@@ -3632,7 +4236,8 @@ async function handleUsersRequest(data, sendMessage) {
|
|
|
3632
4236
|
}, sendMessage);
|
|
3633
4237
|
}
|
|
3634
4238
|
}
|
|
3635
|
-
async function handleCreate(id,
|
|
4239
|
+
async function handleCreate(id, userData, userManager, sendMessage, clientId) {
|
|
4240
|
+
const { username, email, password, fullname, role } = userData;
|
|
3636
4241
|
if (!username || username.trim().length === 0) {
|
|
3637
4242
|
sendResponse3(id, {
|
|
3638
4243
|
success: false,
|
|
@@ -3647,6 +4252,16 @@ async function handleCreate(id, username, password, userManager, sendMessage, cl
|
|
|
3647
4252
|
}, sendMessage, clientId);
|
|
3648
4253
|
return;
|
|
3649
4254
|
}
|
|
4255
|
+
if (email && email.trim().length > 0) {
|
|
4256
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4257
|
+
if (!emailRegex.test(email)) {
|
|
4258
|
+
sendResponse3(id, {
|
|
4259
|
+
success: false,
|
|
4260
|
+
error: "Invalid email format"
|
|
4261
|
+
}, sendMessage, clientId);
|
|
4262
|
+
return;
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
3650
4265
|
if (userManager.userExists(username)) {
|
|
3651
4266
|
sendResponse3(id, {
|
|
3652
4267
|
success: false,
|
|
@@ -3654,25 +4269,41 @@ async function handleCreate(id, username, password, userManager, sendMessage, cl
|
|
|
3654
4269
|
}, sendMessage, clientId);
|
|
3655
4270
|
return;
|
|
3656
4271
|
}
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
4272
|
+
if (email && userManager.getUserByEmail(email)) {
|
|
4273
|
+
sendResponse3(id, {
|
|
4274
|
+
success: false,
|
|
4275
|
+
error: `User with email '${email}' already exists`
|
|
4276
|
+
}, sendMessage, clientId);
|
|
4277
|
+
return;
|
|
3660
4278
|
}
|
|
3661
|
-
const
|
|
4279
|
+
const newUserData = {
|
|
3662
4280
|
username,
|
|
3663
|
-
password
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
4281
|
+
password
|
|
4282
|
+
};
|
|
4283
|
+
if (email && email.trim().length > 0) {
|
|
4284
|
+
newUserData.email = email.trim();
|
|
4285
|
+
}
|
|
4286
|
+
if (fullname && fullname.trim().length > 0) {
|
|
4287
|
+
newUserData.fullname = fullname.trim();
|
|
4288
|
+
}
|
|
4289
|
+
if (role && role.trim().length > 0) {
|
|
4290
|
+
newUserData.role = role.trim();
|
|
4291
|
+
}
|
|
4292
|
+
const newUser = userManager.createUser(newUserData);
|
|
4293
|
+
logger.info(`User created by admin: ${username}${email ? ` (${email})` : ""}`);
|
|
3667
4294
|
sendResponse3(id, {
|
|
3668
4295
|
success: true,
|
|
3669
4296
|
data: {
|
|
3670
4297
|
username: newUser.username,
|
|
4298
|
+
email: newUser.email,
|
|
4299
|
+
fullname: newUser.fullname,
|
|
4300
|
+
role: newUser.role,
|
|
3671
4301
|
message: `User '${username}' created successfully`
|
|
3672
4302
|
}
|
|
3673
4303
|
}, sendMessage, clientId);
|
|
3674
4304
|
}
|
|
3675
|
-
async function handleUpdate(id,
|
|
4305
|
+
async function handleUpdate(id, userData, userManager, sendMessage, clientId) {
|
|
4306
|
+
const { username, email, password, fullname, role } = userData;
|
|
3676
4307
|
if (!username || username.trim().length === 0) {
|
|
3677
4308
|
sendResponse3(id, {
|
|
3678
4309
|
success: false,
|
|
@@ -3688,13 +4319,42 @@ async function handleUpdate(id, username, password, userManager, sendMessage, cl
|
|
|
3688
4319
|
return;
|
|
3689
4320
|
}
|
|
3690
4321
|
const updates = {};
|
|
3691
|
-
if (
|
|
3692
|
-
|
|
4322
|
+
if (email !== void 0) {
|
|
4323
|
+
if (email.trim().length > 0) {
|
|
4324
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4325
|
+
if (!emailRegex.test(email)) {
|
|
4326
|
+
sendResponse3(id, {
|
|
4327
|
+
success: false,
|
|
4328
|
+
error: "Invalid email format"
|
|
4329
|
+
}, sendMessage, clientId);
|
|
4330
|
+
return;
|
|
4331
|
+
}
|
|
4332
|
+
const existingUser = userManager.getUserByEmail(email);
|
|
4333
|
+
if (existingUser && existingUser.username !== username) {
|
|
4334
|
+
sendResponse3(id, {
|
|
4335
|
+
success: false,
|
|
4336
|
+
error: `Email '${email}' is already used by another user`
|
|
4337
|
+
}, sendMessage, clientId);
|
|
4338
|
+
return;
|
|
4339
|
+
}
|
|
4340
|
+
updates.email = email.trim();
|
|
4341
|
+
} else {
|
|
4342
|
+
updates.email = void 0;
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4345
|
+
if (password !== void 0 && password.trim().length > 0) {
|
|
4346
|
+
updates.password = password.trim();
|
|
4347
|
+
}
|
|
4348
|
+
if (fullname !== void 0) {
|
|
4349
|
+
updates.fullname = fullname.trim().length > 0 ? fullname.trim() : void 0;
|
|
4350
|
+
}
|
|
4351
|
+
if (role !== void 0) {
|
|
4352
|
+
updates.role = role.trim().length > 0 ? role.trim() : void 0;
|
|
3693
4353
|
}
|
|
3694
4354
|
if (Object.keys(updates).length === 0) {
|
|
3695
4355
|
sendResponse3(id, {
|
|
3696
4356
|
success: false,
|
|
3697
|
-
error: "No fields to update. Please provide
|
|
4357
|
+
error: "No fields to update. Please provide at least one field to update."
|
|
3698
4358
|
}, sendMessage, clientId);
|
|
3699
4359
|
return;
|
|
3700
4360
|
}
|
|
@@ -3704,6 +4364,9 @@ async function handleUpdate(id, username, password, userManager, sendMessage, cl
|
|
|
3704
4364
|
success: true,
|
|
3705
4365
|
data: {
|
|
3706
4366
|
username: updatedUser.username,
|
|
4367
|
+
email: updatedUser.email,
|
|
4368
|
+
fullname: updatedUser.fullname,
|
|
4369
|
+
role: updatedUser.role,
|
|
3707
4370
|
message: `User '${username}' updated successfully`
|
|
3708
4371
|
}
|
|
3709
4372
|
}, sendMessage, clientId);
|
|
@@ -3744,6 +4407,9 @@ async function handleGetAll(id, userManager, sendMessage, clientId) {
|
|
|
3744
4407
|
const users = userManager.getAllUsers();
|
|
3745
4408
|
const sanitizedUsers = users.map((user) => ({
|
|
3746
4409
|
username: user.username,
|
|
4410
|
+
email: user.email,
|
|
4411
|
+
fullname: user.fullname,
|
|
4412
|
+
role: user.role,
|
|
3747
4413
|
wsIds: user.wsIds || []
|
|
3748
4414
|
}));
|
|
3749
4415
|
logger.info(`Admin retrieved all users (count: ${sanitizedUsers.length})`);
|
|
@@ -3774,6 +4440,9 @@ async function handleGetOne(id, username, userManager, sendMessage, clientId) {
|
|
|
3774
4440
|
const user = userManager.getUser(username);
|
|
3775
4441
|
const sanitizedUser = {
|
|
3776
4442
|
username: user.username,
|
|
4443
|
+
email: user.email,
|
|
4444
|
+
fullname: user.fullname,
|
|
4445
|
+
role: user.role,
|
|
3777
4446
|
wsIds: user.wsIds || []
|
|
3778
4447
|
};
|
|
3779
4448
|
logger.info(`Admin retrieved user: ${username}`);
|
|
@@ -4272,8 +4941,9 @@ var UserManager = class {
|
|
|
4272
4941
|
return;
|
|
4273
4942
|
}
|
|
4274
4943
|
const fileContent = fs4.readFileSync(this.filePath, "utf-8");
|
|
4275
|
-
const
|
|
4276
|
-
|
|
4944
|
+
const rawData = JSON.parse(fileContent);
|
|
4945
|
+
const validatedData = UsersDataSchema.parse(rawData);
|
|
4946
|
+
this.users = validatedData.users;
|
|
4277
4947
|
this.hasChanged = false;
|
|
4278
4948
|
logger.debug(`Loaded ${this.users.length} users from file`);
|
|
4279
4949
|
} catch (error) {
|
|
@@ -4293,10 +4963,14 @@ var UserManager = class {
|
|
|
4293
4963
|
if (!fs4.existsSync(dir)) {
|
|
4294
4964
|
fs4.mkdirSync(dir, { recursive: true });
|
|
4295
4965
|
}
|
|
4296
|
-
const
|
|
4966
|
+
const usersToSave = this.users.map((user) => {
|
|
4967
|
+
const { wsIds, ...userWithoutWsIds } = user;
|
|
4968
|
+
return userWithoutWsIds;
|
|
4969
|
+
});
|
|
4970
|
+
const data = { users: usersToSave };
|
|
4297
4971
|
fs4.writeFileSync(this.filePath, JSON.stringify(data, null, 4));
|
|
4298
4972
|
this.hasChanged = false;
|
|
4299
|
-
logger.debug(`Synced ${this.users.length} users to file`);
|
|
4973
|
+
logger.debug(`Synced ${this.users.length} users to file (wsIds excluded)`);
|
|
4300
4974
|
} catch (error) {
|
|
4301
4975
|
logger.error("Failed to save users to file:", error);
|
|
4302
4976
|
throw new Error(`Failed to save users to file: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -4343,13 +5017,17 @@ var UserManager = class {
|
|
|
4343
5017
|
* @returns The created user
|
|
4344
5018
|
*/
|
|
4345
5019
|
createUser(user) {
|
|
4346
|
-
|
|
4347
|
-
|
|
5020
|
+
const validatedUser = UserSchema.parse(user);
|
|
5021
|
+
if (this.users.some((u) => u.username === validatedUser.username)) {
|
|
5022
|
+
throw new Error(`User with username ${validatedUser.username} already exists`);
|
|
5023
|
+
}
|
|
5024
|
+
if (validatedUser.email && this.users.some((u) => u.email === validatedUser.email)) {
|
|
5025
|
+
throw new Error(`User with email ${validatedUser.email} already exists`);
|
|
4348
5026
|
}
|
|
4349
|
-
this.users.push(
|
|
5027
|
+
this.users.push(validatedUser);
|
|
4350
5028
|
this.hasChanged = true;
|
|
4351
|
-
logger.debug(`User created: ${
|
|
4352
|
-
return
|
|
5029
|
+
logger.debug(`User created: ${validatedUser.username}`);
|
|
5030
|
+
return validatedUser;
|
|
4353
5031
|
}
|
|
4354
5032
|
/**
|
|
4355
5033
|
* Read a user by username
|
|
@@ -4359,6 +5037,22 @@ var UserManager = class {
|
|
|
4359
5037
|
getUser(username) {
|
|
4360
5038
|
return this.users.find((u) => u.username === username);
|
|
4361
5039
|
}
|
|
5040
|
+
/**
|
|
5041
|
+
* Read a user by email
|
|
5042
|
+
* @param email - Email to retrieve
|
|
5043
|
+
* @returns The user if found, undefined otherwise
|
|
5044
|
+
*/
|
|
5045
|
+
getUserByEmail(email) {
|
|
5046
|
+
return this.users.find((u) => u.email === email);
|
|
5047
|
+
}
|
|
5048
|
+
/**
|
|
5049
|
+
* Find user by username or email
|
|
5050
|
+
* @param identifier - Username or email to search for
|
|
5051
|
+
* @returns The user if found, undefined otherwise
|
|
5052
|
+
*/
|
|
5053
|
+
getUserByUsernameOrEmail(identifier) {
|
|
5054
|
+
return this.users.find((u) => u.username === identifier || u.email === identifier);
|
|
5055
|
+
}
|
|
4362
5056
|
/**
|
|
4363
5057
|
* Read all users
|
|
4364
5058
|
* @returns Array of all users
|
|
@@ -4447,7 +5141,6 @@ var UserManager = class {
|
|
|
4447
5141
|
}
|
|
4448
5142
|
if (!user.wsIds.includes(wsId)) {
|
|
4449
5143
|
user.wsIds.push(wsId);
|
|
4450
|
-
this.hasChanged = true;
|
|
4451
5144
|
logger.debug(`WebSocket ID added to user ${username}: ${wsId}`);
|
|
4452
5145
|
}
|
|
4453
5146
|
return true;
|
|
@@ -4469,7 +5162,6 @@ var UserManager = class {
|
|
|
4469
5162
|
const initialLength = user.wsIds.length;
|
|
4470
5163
|
user.wsIds = user.wsIds.filter((id) => id !== wsId);
|
|
4471
5164
|
if (user.wsIds.length < initialLength) {
|
|
4472
|
-
this.hasChanged = true;
|
|
4473
5165
|
logger.debug(`WebSocket ID removed from user ${username}: ${wsId}`);
|
|
4474
5166
|
}
|
|
4475
5167
|
return true;
|
|
@@ -5019,6 +5711,9 @@ var SuperatomSDK = class {
|
|
|
5019
5711
|
this.maxReconnectAttempts = 5;
|
|
5020
5712
|
this.collections = {};
|
|
5021
5713
|
this.components = [];
|
|
5714
|
+
if (config.logLevel) {
|
|
5715
|
+
logger.setLogLevel(config.logLevel);
|
|
5716
|
+
}
|
|
5022
5717
|
this.apiKey = config.apiKey;
|
|
5023
5718
|
this.projectId = config.projectId;
|
|
5024
5719
|
this.userId = config.userId || "anonymous";
|
|
@@ -5321,6 +6016,7 @@ export {
|
|
|
5321
6016
|
ThreadManager,
|
|
5322
6017
|
UIBlock,
|
|
5323
6018
|
UILogCollector,
|
|
5324
|
-
UserManager
|
|
6019
|
+
UserManager,
|
|
6020
|
+
logger
|
|
5325
6021
|
};
|
|
5326
6022
|
//# sourceMappingURL=index.mjs.map
|