@superatomai/sdk-node 0.0.3 → 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 +1016 -305
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1014 -304
- 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);
|
|
@@ -2728,33 +3064,47 @@ var BaseLLM = class {
|
|
|
2728
3064
|
if (classification.visualizations.length > 1) {
|
|
2729
3065
|
const multiMsg = `Matching ${classification.visualizations.length} components for types: ${classification.visualizations.join(", ")}`;
|
|
2730
3066
|
logCollector?.info(multiMsg);
|
|
2731
|
-
const
|
|
2732
|
-
for (const vizType of classification.visualizations) {
|
|
3067
|
+
const componentPromises = classification.visualizations.map((vizType) => {
|
|
2733
3068
|
logCollector?.info(`Matching component for type: ${vizType}`);
|
|
2734
|
-
|
|
3069
|
+
return this.generateAnalyticalComponent(
|
|
2735
3070
|
userPrompt,
|
|
2736
3071
|
components,
|
|
2737
3072
|
vizType,
|
|
2738
3073
|
apiKey,
|
|
2739
3074
|
logCollector,
|
|
2740
3075
|
conversationHistory
|
|
2741
|
-
);
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
3076
|
+
).then((result) => ({ vizType, result }));
|
|
3077
|
+
});
|
|
3078
|
+
const settledResults = await Promise.allSettled(componentPromises);
|
|
3079
|
+
const matchedComponents = [];
|
|
3080
|
+
for (const settledResult of settledResults) {
|
|
3081
|
+
if (settledResult.status === "fulfilled") {
|
|
3082
|
+
const { vizType, result } = settledResult.value;
|
|
3083
|
+
if (result.component) {
|
|
3084
|
+
matchedComponents.push(result.component);
|
|
3085
|
+
logCollector?.info(`Matched: ${result.component.name}`);
|
|
3086
|
+
logger.info("Component : ", result.component.name, " props: ", result.component.props);
|
|
3087
|
+
} else {
|
|
3088
|
+
logCollector?.warn(`Failed to match component for type: ${vizType}`);
|
|
3089
|
+
}
|
|
2745
3090
|
} else {
|
|
2746
|
-
logCollector?.warn(`
|
|
3091
|
+
logCollector?.warn(`Error matching component: ${settledResult.reason?.message || "Unknown error"}`);
|
|
2747
3092
|
}
|
|
2748
3093
|
}
|
|
3094
|
+
logger.debug(`[${this.getProviderName()}] Matched ${matchedComponents.length} components for multi-component container`);
|
|
2749
3095
|
if (matchedComponents.length === 0) {
|
|
2750
3096
|
return {
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
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: []
|
|
2758
3108
|
};
|
|
2759
3109
|
}
|
|
2760
3110
|
logCollector?.info("Generating container metadata...");
|
|
@@ -2784,38 +3134,50 @@ var BaseLLM = class {
|
|
|
2784
3134
|
};
|
|
2785
3135
|
logCollector?.info(`Created multi-component container with ${matchedComponents.length} components: "${containerMetadata.title}"`);
|
|
2786
3136
|
return {
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
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: []
|
|
2794
3148
|
};
|
|
2795
3149
|
} else if (classification.visualizations.length === 1) {
|
|
2796
3150
|
const vizType = classification.visualizations[0];
|
|
2797
3151
|
logCollector?.info(`Matching single component for type: ${vizType}`);
|
|
2798
3152
|
const result = await this.generateAnalyticalComponent(userPrompt, components, vizType, apiKey, logCollector, conversationHistory);
|
|
2799
3153
|
return {
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
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: []
|
|
2807
3165
|
};
|
|
2808
3166
|
} else {
|
|
2809
3167
|
logCollector?.info("No specific visualization type - matching from all components");
|
|
2810
3168
|
const result = await this.generateAnalyticalComponent(userPrompt, components, void 0, apiKey, logCollector, conversationHistory);
|
|
2811
3169
|
return {
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
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: []
|
|
2819
3181
|
};
|
|
2820
3182
|
}
|
|
2821
3183
|
} else if (classification.questionType === "data_modification" || classification.questionType === "general") {
|
|
@@ -2823,28 +3185,109 @@ var BaseLLM = class {
|
|
|
2823
3185
|
logCollector?.info(matchMsg);
|
|
2824
3186
|
const matchResult = await this.matchComponent(userPrompt, components, apiKey, logCollector, conversationHistory);
|
|
2825
3187
|
return {
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
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: []
|
|
2833
3199
|
};
|
|
2834
3200
|
} else {
|
|
2835
3201
|
logCollector?.info("General question - no component needed");
|
|
2836
3202
|
return {
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
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: []
|
|
2842
3214
|
};
|
|
2843
3215
|
}
|
|
2844
3216
|
} catch (error) {
|
|
2845
|
-
|
|
2846
|
-
|
|
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
|
+
};
|
|
2847
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
|
+
};
|
|
2848
3291
|
}
|
|
2849
3292
|
/**
|
|
2850
3293
|
* Generate next questions that the user might ask based on the original prompt and generated component
|
|
@@ -2890,8 +3333,10 @@ var BaseLLM = class {
|
|
|
2890
3333
|
);
|
|
2891
3334
|
return nextQuestions;
|
|
2892
3335
|
} catch (error) {
|
|
2893
|
-
|
|
2894
|
-
|
|
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}`);
|
|
2895
3340
|
return [];
|
|
2896
3341
|
}
|
|
2897
3342
|
}
|
|
@@ -2955,112 +3400,130 @@ function getLLMProviders() {
|
|
|
2955
3400
|
return DEFAULT_PROVIDERS;
|
|
2956
3401
|
}
|
|
2957
3402
|
}
|
|
2958
|
-
var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory) => {
|
|
2959
|
-
|
|
2960
|
-
|
|
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...`;
|
|
2961
3407
|
logCollector?.info(msg);
|
|
2962
|
-
if (components.length === 0) {
|
|
3408
|
+
if (responseMode === "component" && components.length === 0) {
|
|
2963
3409
|
const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
|
|
3410
|
+
logger.error("[useAnthropicMethod] No components available");
|
|
2964
3411
|
logCollector?.error(emptyMsg);
|
|
2965
|
-
return { success: false,
|
|
2966
|
-
}
|
|
2967
|
-
try {
|
|
2968
|
-
const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory);
|
|
2969
|
-
return { success: true, data: matchResult };
|
|
2970
|
-
} catch (error) {
|
|
2971
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2972
|
-
logCollector?.error(`Anthropic method failed: ${errorMsg}`);
|
|
2973
|
-
throw error;
|
|
3412
|
+
return { success: false, errors: [emptyMsg] };
|
|
2974
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;
|
|
2975
3418
|
};
|
|
2976
|
-
var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory) => {
|
|
2977
|
-
|
|
2978
|
-
|
|
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);
|
|
2979
3424
|
logCollector?.info(msg);
|
|
2980
|
-
if (components.length === 0) {
|
|
3425
|
+
if (responseMode === "component" && components.length === 0) {
|
|
2981
3426
|
const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
|
|
3427
|
+
logger.error("[useGroqMethod] No components available");
|
|
2982
3428
|
logCollector?.error(emptyMsg);
|
|
2983
|
-
return { success: false,
|
|
2984
|
-
}
|
|
2985
|
-
try {
|
|
2986
|
-
const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory);
|
|
2987
|
-
return { success: true, data: matchResult };
|
|
2988
|
-
} catch (error) {
|
|
2989
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2990
|
-
logCollector?.error(`Groq method failed: ${errorMsg}`);
|
|
2991
|
-
throw error;
|
|
3429
|
+
return { success: false, errors: [emptyMsg] };
|
|
2992
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;
|
|
2993
3435
|
};
|
|
2994
3436
|
var getUserResponseFromCache = async (prompt) => {
|
|
2995
3437
|
return false;
|
|
2996
3438
|
};
|
|
2997
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");
|
|
2998
3443
|
const userResponse = await getUserResponseFromCache(prompt);
|
|
2999
3444
|
if (userResponse) {
|
|
3445
|
+
logger.info("[get_user_response] User response found in cache - returning cached result");
|
|
3000
3446
|
logCollector?.info("User response found in cache");
|
|
3001
3447
|
return {
|
|
3002
3448
|
success: true,
|
|
3003
|
-
data: userResponse
|
|
3449
|
+
data: userResponse,
|
|
3450
|
+
errors: []
|
|
3004
3451
|
};
|
|
3005
3452
|
}
|
|
3453
|
+
logger.debug("[get_user_response] No cached response found, proceeding with LLM providers");
|
|
3006
3454
|
const providers = llmProviders || getLLMProviders();
|
|
3007
3455
|
const errors = [];
|
|
3008
3456
|
const providerOrder = providers.join(", ");
|
|
3009
3457
|
logCollector?.info(`LLM Provider order: [${providerOrder}]`);
|
|
3010
3458
|
if (conversationHistory && conversationHistory.length > 0) {
|
|
3011
|
-
|
|
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");
|
|
3012
3464
|
}
|
|
3013
3465
|
for (let i = 0; i < providers.length; i++) {
|
|
3014
3466
|
const provider = providers[i];
|
|
3015
3467
|
const isLastProvider = i === providers.length - 1;
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
}
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
const errorMsg = `Provider ${provider} failed: ${errorMessage}`;
|
|
3040
|
-
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);
|
|
3041
3491
|
if (!isLastProvider) {
|
|
3042
3492
|
const fallbackMsg = "Falling back to next provider...";
|
|
3493
|
+
logger.info(`[get_user_response] ${fallbackMsg}`);
|
|
3043
3494
|
logCollector?.info(fallbackMsg);
|
|
3044
|
-
continue;
|
|
3045
3495
|
}
|
|
3046
3496
|
}
|
|
3047
3497
|
}
|
|
3048
|
-
const
|
|
3049
|
-
|
|
3050
|
-
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("; ")}`);
|
|
3051
3501
|
return {
|
|
3052
3502
|
success: false,
|
|
3053
|
-
|
|
3503
|
+
errors
|
|
3054
3504
|
};
|
|
3055
3505
|
};
|
|
3056
3506
|
|
|
3057
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
|
+
};
|
|
3058
3520
|
var UILogCollector = class {
|
|
3059
3521
|
constructor(clientId, sendMessage, uiBlockId) {
|
|
3060
3522
|
this.logs = [];
|
|
3061
3523
|
this.uiBlockId = uiBlockId || null;
|
|
3062
3524
|
this.clientId = clientId;
|
|
3063
3525
|
this.sendMessage = sendMessage;
|
|
3526
|
+
this.currentLogLevel = logger.getLogLevel();
|
|
3064
3527
|
}
|
|
3065
3528
|
/**
|
|
3066
3529
|
* Check if logging is enabled (uiBlockId is provided)
|
|
@@ -3068,10 +3531,22 @@ var UILogCollector = class {
|
|
|
3068
3531
|
isEnabled() {
|
|
3069
3532
|
return this.uiBlockId !== null;
|
|
3070
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
|
+
}
|
|
3071
3542
|
/**
|
|
3072
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
|
|
3073
3545
|
*/
|
|
3074
3546
|
addLog(level, message, type, data) {
|
|
3547
|
+
if (!this.shouldLog(level)) {
|
|
3548
|
+
return;
|
|
3549
|
+
}
|
|
3075
3550
|
const log = {
|
|
3076
3551
|
timestamp: Date.now(),
|
|
3077
3552
|
level,
|
|
@@ -3081,6 +3556,20 @@ var UILogCollector = class {
|
|
|
3081
3556
|
};
|
|
3082
3557
|
this.logs.push(log);
|
|
3083
3558
|
this.sendLogImmediately(log);
|
|
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
|
+
}
|
|
3084
3573
|
}
|
|
3085
3574
|
/**
|
|
3086
3575
|
* Send a single log to runtime immediately
|
|
@@ -3211,100 +3700,131 @@ var CONTEXT_CONFIG = {
|
|
|
3211
3700
|
|
|
3212
3701
|
// src/handlers/user-prompt-request.ts
|
|
3213
3702
|
var processedMessageIds = /* @__PURE__ */ new Set();
|
|
3214
|
-
async
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
const
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
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;
|
|
3231
3787
|
}
|
|
3232
3788
|
}
|
|
3233
|
-
if (!SA_RUNTIME) {
|
|
3234
|
-
sendDataResponse4(id, {
|
|
3235
|
-
success: false,
|
|
3236
|
-
error: "SA_RUNTIME is required"
|
|
3237
|
-
}, sendMessage, wsId);
|
|
3238
|
-
return;
|
|
3239
|
-
}
|
|
3240
|
-
const threadId = SA_RUNTIME.threadId;
|
|
3241
|
-
const existingUiBlockId = SA_RUNTIME.uiBlockId;
|
|
3242
|
-
if (!threadId) {
|
|
3243
|
-
sendDataResponse4(id, {
|
|
3244
|
-
success: false,
|
|
3245
|
-
error: "threadId in SA_RUNTIME is required"
|
|
3246
|
-
}, sendMessage, wsId);
|
|
3247
|
-
return;
|
|
3248
|
-
}
|
|
3249
|
-
if (!existingUiBlockId) {
|
|
3250
|
-
sendDataResponse4(id, {
|
|
3251
|
-
success: false,
|
|
3252
|
-
error: "uiBlockId in SA_RUNTIME is required"
|
|
3253
|
-
}, sendMessage, wsId);
|
|
3254
|
-
return;
|
|
3255
|
-
}
|
|
3256
|
-
const logCollector = new UILogCollector(wsId, sendMessage, existingUiBlockId);
|
|
3257
|
-
if (!prompt) {
|
|
3258
|
-
sendDataResponse4(id, {
|
|
3259
|
-
success: false,
|
|
3260
|
-
error: "Prompt not found"
|
|
3261
|
-
}, sendMessage, wsId);
|
|
3262
|
-
return;
|
|
3263
|
-
}
|
|
3264
|
-
if (!components || components.length === 0) {
|
|
3265
|
-
sendDataResponse4(id, {
|
|
3266
|
-
success: false,
|
|
3267
|
-
error: "Components not found"
|
|
3268
|
-
}, sendMessage, wsId);
|
|
3269
|
-
return;
|
|
3270
|
-
}
|
|
3271
|
-
logCollector.info(`Starting user prompt request with ${components.length} components`);
|
|
3272
|
-
const threadManager = ThreadManager.getInstance();
|
|
3273
|
-
let thread = threadManager.getThread(threadId);
|
|
3274
|
-
if (!thread) {
|
|
3275
|
-
thread = threadManager.createThread(threadId);
|
|
3276
|
-
logger.info(`Created new thread: ${threadId}`);
|
|
3277
|
-
}
|
|
3278
|
-
const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
|
|
3279
|
-
const userResponse = await get_user_response(prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory);
|
|
3280
|
-
logCollector.info("User prompt request completed");
|
|
3281
|
-
if (userResponse.success && userResponse.data && typeof userResponse.data === "object" && "component" in userResponse.data) {
|
|
3282
|
-
const component = userResponse.data.component;
|
|
3283
|
-
const uiBlockId = existingUiBlockId;
|
|
3284
|
-
const uiBlock = new UIBlock(
|
|
3285
|
-
prompt,
|
|
3286
|
-
{},
|
|
3287
|
-
// componentData: initially empty, will be filled later
|
|
3288
|
-
component || {},
|
|
3289
|
-
// generatedComponentMetadata: full component object (ComponentSchema)
|
|
3290
|
-
[],
|
|
3291
|
-
// actions: empty initially
|
|
3292
|
-
uiBlockId
|
|
3293
|
-
);
|
|
3294
|
-
thread.addUIBlock(uiBlock);
|
|
3295
|
-
logger.info(`Created UIBlock: ${uiBlockId} in Thread: ${threadId}`);
|
|
3296
|
-
sendDataResponse4(id, {
|
|
3297
|
-
...userResponse,
|
|
3298
|
-
uiBlockId,
|
|
3299
|
-
threadId
|
|
3300
|
-
}, sendMessage, wsId);
|
|
3301
|
-
} else {
|
|
3302
|
-
sendDataResponse4(id, userResponse, sendMessage, wsId);
|
|
3303
|
-
}
|
|
3304
|
-
return;
|
|
3305
|
-
} catch (error) {
|
|
3306
|
-
logger.error("Failed to handle user prompt request:", error);
|
|
3307
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
|
+
);
|
|
3308
3828
|
}
|
|
3309
3829
|
function sendDataResponse4(id, res, sendMessage, clientId) {
|
|
3310
3830
|
const response = {
|
|
@@ -3319,6 +3839,7 @@ function sendDataResponse4(id, res, sendMessage, clientId) {
|
|
|
3319
3839
|
...res
|
|
3320
3840
|
}
|
|
3321
3841
|
};
|
|
3842
|
+
logger.info("sending user prompt response", response);
|
|
3322
3843
|
sendMessage(response);
|
|
3323
3844
|
}
|
|
3324
3845
|
|
|
@@ -3416,12 +3937,27 @@ function sendResponse(id, res, sendMessage, clientId) {
|
|
|
3416
3937
|
// src/userResponse/next-questions.ts
|
|
3417
3938
|
async function generateNextQuestions(originalUserPrompt, component, componentData, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory) {
|
|
3418
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"}`);
|
|
3419
3944
|
const providers = llmProviders || ["anthropic"];
|
|
3420
|
-
|
|
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;
|
|
3421
3955
|
try {
|
|
3422
|
-
logger.info(`
|
|
3956
|
+
logger.info(`[generateNextQuestions] Attempting provider: ${provider} (${i + 1}/${providers.length})`);
|
|
3957
|
+
logCollector?.info(`Generating questions with ${provider}...`);
|
|
3423
3958
|
let result = [];
|
|
3424
3959
|
if (provider === "groq") {
|
|
3960
|
+
logger.debug("[generateNextQuestions] Using Groq LLM for next questions");
|
|
3425
3961
|
result = await groqLLM.generateNextQuestions(
|
|
3426
3962
|
originalUserPrompt,
|
|
3427
3963
|
component,
|
|
@@ -3431,6 +3967,7 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
|
|
|
3431
3967
|
conversationHistory
|
|
3432
3968
|
);
|
|
3433
3969
|
} else {
|
|
3970
|
+
logger.debug("[generateNextQuestions] Using Anthropic LLM for next questions");
|
|
3434
3971
|
result = await anthropicLLM.generateNextQuestions(
|
|
3435
3972
|
originalUserPrompt,
|
|
3436
3973
|
component,
|
|
@@ -3441,21 +3978,39 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
|
|
|
3441
3978
|
);
|
|
3442
3979
|
}
|
|
3443
3980
|
if (result && result.length > 0) {
|
|
3444
|
-
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`);
|
|
3445
3984
|
return result;
|
|
3446
3985
|
}
|
|
3447
|
-
|
|
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
|
+
}
|
|
3448
3991
|
} catch (providerError) {
|
|
3449
|
-
|
|
3450
|
-
|
|
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
|
+
}
|
|
3451
4002
|
continue;
|
|
3452
4003
|
}
|
|
3453
4004
|
}
|
|
3454
|
-
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");
|
|
3455
4007
|
return [];
|
|
3456
4008
|
} catch (error) {
|
|
3457
|
-
|
|
3458
|
-
|
|
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}`);
|
|
3459
4014
|
return [];
|
|
3460
4015
|
}
|
|
3461
4016
|
}
|
|
@@ -3463,11 +4018,15 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
|
|
|
3463
4018
|
// src/handlers/actions-request.ts
|
|
3464
4019
|
async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiKey, llmProviders) {
|
|
3465
4020
|
try {
|
|
4021
|
+
logger.debug("[ACTIONS_REQ] Parsing incoming actions request");
|
|
3466
4022
|
const actionsRequest = ActionsRequestMessageSchema.parse(data);
|
|
3467
4023
|
const { id, payload } = actionsRequest;
|
|
3468
4024
|
const { SA_RUNTIME } = payload;
|
|
3469
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));
|
|
3470
4028
|
if (!SA_RUNTIME) {
|
|
4029
|
+
logger.error(`[ACTIONS_REQ ${id}] SA_RUNTIME missing from request`);
|
|
3471
4030
|
sendResponse2(id, {
|
|
3472
4031
|
success: false,
|
|
3473
4032
|
error: "SA_RUNTIME with threadId and uiBlockId is required"
|
|
@@ -3476,31 +4035,54 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
|
|
|
3476
4035
|
}
|
|
3477
4036
|
const uiBlockId = SA_RUNTIME.uiBlockId;
|
|
3478
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}`);
|
|
3479
4040
|
const threadManager = ThreadManager.getInstance();
|
|
3480
4041
|
const thread = threadManager.getThread(threadId);
|
|
3481
4042
|
if (!thread) {
|
|
4043
|
+
logger.error(`[ACTIONS_REQ ${id}] Thread '${threadId}' not found`);
|
|
3482
4044
|
sendResponse2(id, {
|
|
3483
4045
|
success: false,
|
|
3484
4046
|
error: `Thread '${threadId}' not found`
|
|
3485
4047
|
}, sendMessage, wsId);
|
|
3486
4048
|
return;
|
|
3487
4049
|
}
|
|
4050
|
+
logger.debug(`[ACTIONS_REQ ${id}] Thread found with ${thread.getUIBlocks().length} UIBlocks`);
|
|
4051
|
+
logger.debug(`[ACTIONS_REQ ${id}] Retrieving UIBlock: ${uiBlockId}`);
|
|
3488
4052
|
const uiBlock = thread.getUIBlock(uiBlockId);
|
|
3489
4053
|
if (!uiBlock) {
|
|
4054
|
+
logger.error(`[ACTIONS_REQ ${id}] UIBlock '${uiBlockId}' not found in thread '${threadId}'`);
|
|
3490
4055
|
sendResponse2(id, {
|
|
3491
4056
|
success: false,
|
|
3492
4057
|
error: `UIBlock '${uiBlockId}' not found in thread '${threadId}'`
|
|
3493
4058
|
}, sendMessage, wsId);
|
|
3494
4059
|
return;
|
|
3495
4060
|
}
|
|
4061
|
+
logger.info(`[ACTIONS_REQ ${id}] UIBlock retrieved successfully`);
|
|
4062
|
+
logger.debug(`[ACTIONS_REQ ${id}] Creating UILogCollector for uiBlockId: ${uiBlockId}`);
|
|
3496
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`);
|
|
3497
4066
|
const userQuestion = uiBlock.getUserQuestion();
|
|
3498
4067
|
const component = uiBlock.getComponentMetadata();
|
|
3499
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)`);
|
|
3500
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)}...`);
|
|
3501
4078
|
logCollector.info(`Generating actions for UIBlock: ${uiBlockId}`);
|
|
3502
|
-
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();
|
|
3503
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`);
|
|
3504
4086
|
const nextQuestions = await generateNextQuestions(
|
|
3505
4087
|
userQuestion,
|
|
3506
4088
|
component,
|
|
@@ -3511,14 +4093,28 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
|
|
|
3511
4093
|
logCollector,
|
|
3512
4094
|
conversationHistory
|
|
3513
4095
|
);
|
|
3514
|
-
|
|
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) => ({
|
|
3515
4100
|
id: `action_${index}_${Date.now()}`,
|
|
3516
4101
|
name: question,
|
|
3517
4102
|
type: "next_question",
|
|
3518
4103
|
question
|
|
3519
4104
|
}));
|
|
4105
|
+
logger.debug(`[ACTIONS_REQ ${id}] Converted ${convertedActions.length} actions`);
|
|
4106
|
+
return convertedActions;
|
|
3520
4107
|
});
|
|
3521
|
-
|
|
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`);
|
|
3522
4118
|
sendResponse2(id, {
|
|
3523
4119
|
success: true,
|
|
3524
4120
|
data: {
|
|
@@ -3529,12 +4125,26 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
|
|
|
3529
4125
|
threadId
|
|
3530
4126
|
}
|
|
3531
4127
|
}, sendMessage, wsId);
|
|
4128
|
+
logger.info(`[ACTIONS_REQ ${id}] \u2713 Actions request completed successfully`);
|
|
3532
4129
|
} catch (error) {
|
|
3533
|
-
|
|
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
|
+
}
|
|
3534
4143
|
sendResponse2(null, {
|
|
3535
4144
|
success: false,
|
|
3536
|
-
error:
|
|
4145
|
+
error: errorMessage
|
|
3537
4146
|
}, sendMessage);
|
|
4147
|
+
logger.info("[ACTIONS_REQ] \u2717 Actions request completed with errors");
|
|
3538
4148
|
}
|
|
3539
4149
|
}
|
|
3540
4150
|
function sendResponse2(id, res, sendMessage, clientId) {
|
|
@@ -3550,6 +4160,11 @@ function sendResponse2(id, res, sendMessage, clientId) {
|
|
|
3550
4160
|
...res
|
|
3551
4161
|
}
|
|
3552
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
|
+
}
|
|
3553
4168
|
sendMessage(response);
|
|
3554
4169
|
}
|
|
3555
4170
|
|
|
@@ -3578,7 +4193,10 @@ async function handleUsersRequest(data, sendMessage) {
|
|
|
3578
4193
|
const { id, payload, from } = request;
|
|
3579
4194
|
const { operation, data: requestData } = payload;
|
|
3580
4195
|
const username = requestData?.username;
|
|
4196
|
+
const email = requestData?.email;
|
|
3581
4197
|
const password = requestData?.password;
|
|
4198
|
+
const fullname = requestData?.fullname;
|
|
4199
|
+
const role = requestData?.role;
|
|
3582
4200
|
if (from.type !== "admin") {
|
|
3583
4201
|
sendResponse3(id, {
|
|
3584
4202
|
success: false,
|
|
@@ -3590,10 +4208,10 @@ async function handleUsersRequest(data, sendMessage) {
|
|
|
3590
4208
|
const userManager = getUserManager();
|
|
3591
4209
|
switch (operation) {
|
|
3592
4210
|
case "create":
|
|
3593
|
-
await handleCreate(id, username, password, userManager, sendMessage, from.id);
|
|
4211
|
+
await handleCreate(id, { username, email, password, fullname, role }, userManager, sendMessage, from.id);
|
|
3594
4212
|
break;
|
|
3595
4213
|
case "update":
|
|
3596
|
-
await handleUpdate(id, username, password, userManager, sendMessage, from.id);
|
|
4214
|
+
await handleUpdate(id, { username, email, password, fullname, role }, userManager, sendMessage, from.id);
|
|
3597
4215
|
break;
|
|
3598
4216
|
case "delete":
|
|
3599
4217
|
await handleDelete(id, username, userManager, sendMessage, from.id);
|
|
@@ -3618,7 +4236,8 @@ async function handleUsersRequest(data, sendMessage) {
|
|
|
3618
4236
|
}, sendMessage);
|
|
3619
4237
|
}
|
|
3620
4238
|
}
|
|
3621
|
-
async function handleCreate(id,
|
|
4239
|
+
async function handleCreate(id, userData, userManager, sendMessage, clientId) {
|
|
4240
|
+
const { username, email, password, fullname, role } = userData;
|
|
3622
4241
|
if (!username || username.trim().length === 0) {
|
|
3623
4242
|
sendResponse3(id, {
|
|
3624
4243
|
success: false,
|
|
@@ -3633,6 +4252,16 @@ async function handleCreate(id, username, password, userManager, sendMessage, cl
|
|
|
3633
4252
|
}, sendMessage, clientId);
|
|
3634
4253
|
return;
|
|
3635
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
|
+
}
|
|
3636
4265
|
if (userManager.userExists(username)) {
|
|
3637
4266
|
sendResponse3(id, {
|
|
3638
4267
|
success: false,
|
|
@@ -3640,25 +4269,41 @@ async function handleCreate(id, username, password, userManager, sendMessage, cl
|
|
|
3640
4269
|
}, sendMessage, clientId);
|
|
3641
4270
|
return;
|
|
3642
4271
|
}
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
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;
|
|
3646
4278
|
}
|
|
3647
|
-
const
|
|
4279
|
+
const newUserData = {
|
|
3648
4280
|
username,
|
|
3649
|
-
password
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
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})` : ""}`);
|
|
3653
4294
|
sendResponse3(id, {
|
|
3654
4295
|
success: true,
|
|
3655
4296
|
data: {
|
|
3656
4297
|
username: newUser.username,
|
|
4298
|
+
email: newUser.email,
|
|
4299
|
+
fullname: newUser.fullname,
|
|
4300
|
+
role: newUser.role,
|
|
3657
4301
|
message: `User '${username}' created successfully`
|
|
3658
4302
|
}
|
|
3659
4303
|
}, sendMessage, clientId);
|
|
3660
4304
|
}
|
|
3661
|
-
async function handleUpdate(id,
|
|
4305
|
+
async function handleUpdate(id, userData, userManager, sendMessage, clientId) {
|
|
4306
|
+
const { username, email, password, fullname, role } = userData;
|
|
3662
4307
|
if (!username || username.trim().length === 0) {
|
|
3663
4308
|
sendResponse3(id, {
|
|
3664
4309
|
success: false,
|
|
@@ -3674,13 +4319,42 @@ async function handleUpdate(id, username, password, userManager, sendMessage, cl
|
|
|
3674
4319
|
return;
|
|
3675
4320
|
}
|
|
3676
4321
|
const updates = {};
|
|
3677
|
-
if (
|
|
3678
|
-
|
|
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;
|
|
3679
4353
|
}
|
|
3680
4354
|
if (Object.keys(updates).length === 0) {
|
|
3681
4355
|
sendResponse3(id, {
|
|
3682
4356
|
success: false,
|
|
3683
|
-
error: "No fields to update. Please provide
|
|
4357
|
+
error: "No fields to update. Please provide at least one field to update."
|
|
3684
4358
|
}, sendMessage, clientId);
|
|
3685
4359
|
return;
|
|
3686
4360
|
}
|
|
@@ -3690,6 +4364,9 @@ async function handleUpdate(id, username, password, userManager, sendMessage, cl
|
|
|
3690
4364
|
success: true,
|
|
3691
4365
|
data: {
|
|
3692
4366
|
username: updatedUser.username,
|
|
4367
|
+
email: updatedUser.email,
|
|
4368
|
+
fullname: updatedUser.fullname,
|
|
4369
|
+
role: updatedUser.role,
|
|
3693
4370
|
message: `User '${username}' updated successfully`
|
|
3694
4371
|
}
|
|
3695
4372
|
}, sendMessage, clientId);
|
|
@@ -3730,6 +4407,9 @@ async function handleGetAll(id, userManager, sendMessage, clientId) {
|
|
|
3730
4407
|
const users = userManager.getAllUsers();
|
|
3731
4408
|
const sanitizedUsers = users.map((user) => ({
|
|
3732
4409
|
username: user.username,
|
|
4410
|
+
email: user.email,
|
|
4411
|
+
fullname: user.fullname,
|
|
4412
|
+
role: user.role,
|
|
3733
4413
|
wsIds: user.wsIds || []
|
|
3734
4414
|
}));
|
|
3735
4415
|
logger.info(`Admin retrieved all users (count: ${sanitizedUsers.length})`);
|
|
@@ -3760,6 +4440,9 @@ async function handleGetOne(id, username, userManager, sendMessage, clientId) {
|
|
|
3760
4440
|
const user = userManager.getUser(username);
|
|
3761
4441
|
const sanitizedUser = {
|
|
3762
4442
|
username: user.username,
|
|
4443
|
+
email: user.email,
|
|
4444
|
+
fullname: user.fullname,
|
|
4445
|
+
role: user.role,
|
|
3763
4446
|
wsIds: user.wsIds || []
|
|
3764
4447
|
};
|
|
3765
4448
|
logger.info(`Admin retrieved user: ${username}`);
|
|
@@ -4258,8 +4941,9 @@ var UserManager = class {
|
|
|
4258
4941
|
return;
|
|
4259
4942
|
}
|
|
4260
4943
|
const fileContent = fs4.readFileSync(this.filePath, "utf-8");
|
|
4261
|
-
const
|
|
4262
|
-
|
|
4944
|
+
const rawData = JSON.parse(fileContent);
|
|
4945
|
+
const validatedData = UsersDataSchema.parse(rawData);
|
|
4946
|
+
this.users = validatedData.users;
|
|
4263
4947
|
this.hasChanged = false;
|
|
4264
4948
|
logger.debug(`Loaded ${this.users.length} users from file`);
|
|
4265
4949
|
} catch (error) {
|
|
@@ -4279,10 +4963,14 @@ var UserManager = class {
|
|
|
4279
4963
|
if (!fs4.existsSync(dir)) {
|
|
4280
4964
|
fs4.mkdirSync(dir, { recursive: true });
|
|
4281
4965
|
}
|
|
4282
|
-
const
|
|
4966
|
+
const usersToSave = this.users.map((user) => {
|
|
4967
|
+
const { wsIds, ...userWithoutWsIds } = user;
|
|
4968
|
+
return userWithoutWsIds;
|
|
4969
|
+
});
|
|
4970
|
+
const data = { users: usersToSave };
|
|
4283
4971
|
fs4.writeFileSync(this.filePath, JSON.stringify(data, null, 4));
|
|
4284
4972
|
this.hasChanged = false;
|
|
4285
|
-
logger.debug(`Synced ${this.users.length} users to file`);
|
|
4973
|
+
logger.debug(`Synced ${this.users.length} users to file (wsIds excluded)`);
|
|
4286
4974
|
} catch (error) {
|
|
4287
4975
|
logger.error("Failed to save users to file:", error);
|
|
4288
4976
|
throw new Error(`Failed to save users to file: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -4329,13 +5017,17 @@ var UserManager = class {
|
|
|
4329
5017
|
* @returns The created user
|
|
4330
5018
|
*/
|
|
4331
5019
|
createUser(user) {
|
|
4332
|
-
|
|
4333
|
-
|
|
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`);
|
|
4334
5023
|
}
|
|
4335
|
-
this.users.
|
|
5024
|
+
if (validatedUser.email && this.users.some((u) => u.email === validatedUser.email)) {
|
|
5025
|
+
throw new Error(`User with email ${validatedUser.email} already exists`);
|
|
5026
|
+
}
|
|
5027
|
+
this.users.push(validatedUser);
|
|
4336
5028
|
this.hasChanged = true;
|
|
4337
|
-
logger.debug(`User created: ${
|
|
4338
|
-
return
|
|
5029
|
+
logger.debug(`User created: ${validatedUser.username}`);
|
|
5030
|
+
return validatedUser;
|
|
4339
5031
|
}
|
|
4340
5032
|
/**
|
|
4341
5033
|
* Read a user by username
|
|
@@ -4345,6 +5037,22 @@ var UserManager = class {
|
|
|
4345
5037
|
getUser(username) {
|
|
4346
5038
|
return this.users.find((u) => u.username === username);
|
|
4347
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
|
+
}
|
|
4348
5056
|
/**
|
|
4349
5057
|
* Read all users
|
|
4350
5058
|
* @returns Array of all users
|
|
@@ -4433,7 +5141,6 @@ var UserManager = class {
|
|
|
4433
5141
|
}
|
|
4434
5142
|
if (!user.wsIds.includes(wsId)) {
|
|
4435
5143
|
user.wsIds.push(wsId);
|
|
4436
|
-
this.hasChanged = true;
|
|
4437
5144
|
logger.debug(`WebSocket ID added to user ${username}: ${wsId}`);
|
|
4438
5145
|
}
|
|
4439
5146
|
return true;
|
|
@@ -4455,7 +5162,6 @@ var UserManager = class {
|
|
|
4455
5162
|
const initialLength = user.wsIds.length;
|
|
4456
5163
|
user.wsIds = user.wsIds.filter((id) => id !== wsId);
|
|
4457
5164
|
if (user.wsIds.length < initialLength) {
|
|
4458
|
-
this.hasChanged = true;
|
|
4459
5165
|
logger.debug(`WebSocket ID removed from user ${username}: ${wsId}`);
|
|
4460
5166
|
}
|
|
4461
5167
|
return true;
|
|
@@ -5005,6 +5711,9 @@ var SuperatomSDK = class {
|
|
|
5005
5711
|
this.maxReconnectAttempts = 5;
|
|
5006
5712
|
this.collections = {};
|
|
5007
5713
|
this.components = [];
|
|
5714
|
+
if (config.logLevel) {
|
|
5715
|
+
logger.setLogLevel(config.logLevel);
|
|
5716
|
+
}
|
|
5008
5717
|
this.apiKey = config.apiKey;
|
|
5009
5718
|
this.projectId = config.projectId;
|
|
5010
5719
|
this.userId = config.userId || "anonymous";
|
|
@@ -5307,6 +6016,7 @@ export {
|
|
|
5307
6016
|
ThreadManager,
|
|
5308
6017
|
UIBlock,
|
|
5309
6018
|
UILogCollector,
|
|
5310
|
-
UserManager
|
|
6019
|
+
UserManager,
|
|
6020
|
+
logger
|
|
5311
6021
|
};
|
|
5312
6022
|
//# sourceMappingURL=index.mjs.map
|