@superatomai/sdk-node 0.0.5 → 0.0.6
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 +251 -33
- package/dist/index.d.mts +13 -4
- package/dist/index.d.ts +13 -4
- package/dist/index.js +809 -252
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +813 -252
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -10,9 +10,16 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
10
10
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
11
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
12
|
});
|
|
13
|
+
var __esm = (fn, res) => function __init() {
|
|
14
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
15
|
+
};
|
|
13
16
|
var __commonJS = (cb, mod) => function __require2() {
|
|
14
17
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
15
18
|
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
22
|
+
};
|
|
16
23
|
var __copyProps = (to, from, except, desc) => {
|
|
17
24
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
25
|
for (let key of __getOwnPropNames(from))
|
|
@@ -102,7 +109,7 @@ var require_package = __commonJS({
|
|
|
102
109
|
var require_main = __commonJS({
|
|
103
110
|
"node_modules/dotenv/lib/main.js"(exports, module) {
|
|
104
111
|
"use strict";
|
|
105
|
-
var
|
|
112
|
+
var fs8 = __require("fs");
|
|
106
113
|
var path7 = __require("path");
|
|
107
114
|
var os4 = __require("os");
|
|
108
115
|
var crypto2 = __require("crypto");
|
|
@@ -244,7 +251,7 @@ var require_main = __commonJS({
|
|
|
244
251
|
if (options && options.path && options.path.length > 0) {
|
|
245
252
|
if (Array.isArray(options.path)) {
|
|
246
253
|
for (const filepath of options.path) {
|
|
247
|
-
if (
|
|
254
|
+
if (fs8.existsSync(filepath)) {
|
|
248
255
|
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
249
256
|
}
|
|
250
257
|
}
|
|
@@ -254,7 +261,7 @@ var require_main = __commonJS({
|
|
|
254
261
|
} else {
|
|
255
262
|
possibleVaultPath = path7.resolve(process.cwd(), ".env.vault");
|
|
256
263
|
}
|
|
257
|
-
if (
|
|
264
|
+
if (fs8.existsSync(possibleVaultPath)) {
|
|
258
265
|
return possibleVaultPath;
|
|
259
266
|
}
|
|
260
267
|
return null;
|
|
@@ -307,7 +314,7 @@ var require_main = __commonJS({
|
|
|
307
314
|
const parsedAll = {};
|
|
308
315
|
for (const path8 of optionPaths) {
|
|
309
316
|
try {
|
|
310
|
-
const parsed = DotenvModule.parse(
|
|
317
|
+
const parsed = DotenvModule.parse(fs8.readFileSync(path8, { encoding }));
|
|
311
318
|
DotenvModule.populate(parsedAll, parsed, options);
|
|
312
319
|
} catch (e) {
|
|
313
320
|
if (debug) {
|
|
@@ -428,6 +435,128 @@ var require_main = __commonJS({
|
|
|
428
435
|
}
|
|
429
436
|
});
|
|
430
437
|
|
|
438
|
+
// src/userResponse/utils.ts
|
|
439
|
+
var utils_exports = {};
|
|
440
|
+
__export(utils_exports, {
|
|
441
|
+
convertTopToLimit: () => convertTopToLimit,
|
|
442
|
+
ensureQueryLimit: () => ensureQueryLimit,
|
|
443
|
+
fixScalarSubqueries: () => fixScalarSubqueries,
|
|
444
|
+
getJsonSizeInBytes: () => getJsonSizeInBytes,
|
|
445
|
+
validateMessageSize: () => validateMessageSize
|
|
446
|
+
});
|
|
447
|
+
function convertTopToLimit(query) {
|
|
448
|
+
if (!query || query.trim().length === 0) {
|
|
449
|
+
return query;
|
|
450
|
+
}
|
|
451
|
+
let modifiedQuery = query.replace(/\bSELECT\s+TOP\s+(\d+)\b/gi, "SELECT");
|
|
452
|
+
if (modifiedQuery !== query) {
|
|
453
|
+
console.warn(`\u26A0\uFE0F Query had TOP syntax. Converting to LIMIT for Snowflake compatibility.`);
|
|
454
|
+
}
|
|
455
|
+
return modifiedQuery;
|
|
456
|
+
}
|
|
457
|
+
function ensureQueryLimit(query, defaultLimit = 32, maxLimit = 32) {
|
|
458
|
+
if (!query || query.trim().length === 0) {
|
|
459
|
+
return query;
|
|
460
|
+
}
|
|
461
|
+
let trimmedQuery = query.trim();
|
|
462
|
+
const isSelectQuery = /^\s*SELECT\b/i.test(trimmedQuery) || /^\s*WITH\b.*\bSELECT\b/is.test(trimmedQuery);
|
|
463
|
+
if (!isSelectQuery) {
|
|
464
|
+
return query;
|
|
465
|
+
}
|
|
466
|
+
trimmedQuery = convertTopToLimit(trimmedQuery);
|
|
467
|
+
const hadSemicolon = trimmedQuery.endsWith(";");
|
|
468
|
+
if (hadSemicolon) {
|
|
469
|
+
trimmedQuery = trimmedQuery.slice(0, -1).trim();
|
|
470
|
+
}
|
|
471
|
+
const limitMatches = trimmedQuery.match(/\bLIMIT\s+(\d+)\b/gi);
|
|
472
|
+
if (limitMatches && limitMatches.length > 0) {
|
|
473
|
+
if (limitMatches.length > 1) {
|
|
474
|
+
console.warn(`\u26A0\uFE0F Query had ${limitMatches.length} LIMIT clauses. Removing duplicates...`);
|
|
475
|
+
trimmedQuery = trimmedQuery.replace(/\s*\bLIMIT\s+\d+\b/gi, "").trim();
|
|
476
|
+
} else {
|
|
477
|
+
const existingLimitMatch = trimmedQuery.match(/\bLIMIT\s+(\d+)\b/i);
|
|
478
|
+
if (existingLimitMatch) {
|
|
479
|
+
const existingLimit = parseInt(existingLimitMatch[1], 10);
|
|
480
|
+
if (existingLimit <= maxLimit) {
|
|
481
|
+
if (hadSemicolon) {
|
|
482
|
+
trimmedQuery += ";";
|
|
483
|
+
}
|
|
484
|
+
return trimmedQuery;
|
|
485
|
+
}
|
|
486
|
+
console.warn(`\u26A0\uFE0F Query LIMIT ${existingLimit} exceeds maximum of ${maxLimit}. Reducing to ${maxLimit}...`);
|
|
487
|
+
trimmedQuery = trimmedQuery.replace(/\bLIMIT\s+\d+\b/i, `LIMIT ${maxLimit}`);
|
|
488
|
+
if (hadSemicolon) {
|
|
489
|
+
trimmedQuery += ";";
|
|
490
|
+
}
|
|
491
|
+
return trimmedQuery;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
trimmedQuery = `${trimmedQuery} LIMIT ${defaultLimit}`;
|
|
496
|
+
if (hadSemicolon) {
|
|
497
|
+
trimmedQuery += ";";
|
|
498
|
+
}
|
|
499
|
+
return trimmedQuery;
|
|
500
|
+
}
|
|
501
|
+
function fixScalarSubqueries(query) {
|
|
502
|
+
if (!query || query.trim().length === 0) {
|
|
503
|
+
return query;
|
|
504
|
+
}
|
|
505
|
+
let modifiedQuery = query;
|
|
506
|
+
let hasChanges = false;
|
|
507
|
+
const scalarOperatorPattern = /([=<>!]=?|<>)\s*\(\s*SELECT\s/gi;
|
|
508
|
+
const matches = [...modifiedQuery.matchAll(scalarOperatorPattern)];
|
|
509
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
510
|
+
const match = matches[i];
|
|
511
|
+
const startPos = match.index + match[0].length - "SELECT ".length;
|
|
512
|
+
let parenDepth = 1;
|
|
513
|
+
let endPos = startPos;
|
|
514
|
+
let foundEnd = false;
|
|
515
|
+
for (let j = startPos; j < modifiedQuery.length; j++) {
|
|
516
|
+
const char = modifiedQuery[j];
|
|
517
|
+
if (char === "(") parenDepth++;
|
|
518
|
+
if (char === ")") {
|
|
519
|
+
parenDepth--;
|
|
520
|
+
if (parenDepth === 0) {
|
|
521
|
+
endPos = j;
|
|
522
|
+
foundEnd = true;
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if (!foundEnd) continue;
|
|
528
|
+
const subquery = modifiedQuery.substring(startPos, endPos);
|
|
529
|
+
if (/\bLIMIT\s+\d+/i.test(subquery)) {
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
const fixedSubquery = subquery.trim() + " LIMIT 1";
|
|
533
|
+
modifiedQuery = modifiedQuery.substring(0, startPos) + fixedSubquery + modifiedQuery.substring(endPos);
|
|
534
|
+
hasChanges = true;
|
|
535
|
+
console.warn(`\u26A0\uFE0F Fixed scalar subquery: added LIMIT 1 to prevent multiple row error`);
|
|
536
|
+
}
|
|
537
|
+
if (hasChanges) {
|
|
538
|
+
console.log("\u2713 Query validated and fixed for PostgreSQL scalar subquery compatibility");
|
|
539
|
+
}
|
|
540
|
+
return modifiedQuery;
|
|
541
|
+
}
|
|
542
|
+
function getJsonSizeInBytes(obj) {
|
|
543
|
+
const jsonString = JSON.stringify(obj);
|
|
544
|
+
return Buffer.byteLength(jsonString, "utf8");
|
|
545
|
+
}
|
|
546
|
+
function validateMessageSize(message, maxSize = 1048576) {
|
|
547
|
+
const size = getJsonSizeInBytes(message);
|
|
548
|
+
return {
|
|
549
|
+
isValid: size <= maxSize,
|
|
550
|
+
size,
|
|
551
|
+
maxSize
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
var init_utils = __esm({
|
|
555
|
+
"src/userResponse/utils.ts"() {
|
|
556
|
+
"use strict";
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
|
|
431
560
|
// src/websocket.ts
|
|
432
561
|
import WebSocket from "ws";
|
|
433
562
|
function createWebSocket(url) {
|
|
@@ -689,7 +818,8 @@ var UserPromptRequestPayloadSchema = z3.object({
|
|
|
689
818
|
SA_RUNTIME: z3.object({
|
|
690
819
|
threadId: z3.string(),
|
|
691
820
|
uiBlockId: z3.string()
|
|
692
|
-
}).optional()
|
|
821
|
+
}).optional(),
|
|
822
|
+
responseMode: z3.enum(["component", "text"]).optional()
|
|
693
823
|
});
|
|
694
824
|
var UserPromptRequestMessageSchema = z3.object({
|
|
695
825
|
id: z3.string(),
|
|
@@ -804,7 +934,9 @@ var ReportsRequestMessageSchema = z3.object({
|
|
|
804
934
|
});
|
|
805
935
|
|
|
806
936
|
// src/utils/logger.ts
|
|
937
|
+
import fs from "fs";
|
|
807
938
|
var PREFIX = "[SuperatomSDK]";
|
|
939
|
+
var LOGSTREAM = fs.createWriteStream("superatom-sdk.log", { flags: "a" });
|
|
808
940
|
var LOG_LEVEL_PRIORITY = {
|
|
809
941
|
errors: 0,
|
|
810
942
|
warnings: 1,
|
|
@@ -888,6 +1020,9 @@ var Logger = class {
|
|
|
888
1020
|
console.log(PREFIX, "[DEBUG]", ...args);
|
|
889
1021
|
}
|
|
890
1022
|
}
|
|
1023
|
+
file(...args) {
|
|
1024
|
+
LOGSTREAM.write(args.join(" ") + "\n");
|
|
1025
|
+
}
|
|
891
1026
|
};
|
|
892
1027
|
var logger = new Logger();
|
|
893
1028
|
|
|
@@ -959,6 +1094,9 @@ var UIBlock = class {
|
|
|
959
1094
|
getComponentMetadata() {
|
|
960
1095
|
return this.generatedComponentMetadata;
|
|
961
1096
|
}
|
|
1097
|
+
getTextResponse() {
|
|
1098
|
+
return this.textResponse || "";
|
|
1099
|
+
}
|
|
962
1100
|
/**
|
|
963
1101
|
* Set or update component metadata
|
|
964
1102
|
*/
|
|
@@ -1051,12 +1189,6 @@ var UIBlock = class {
|
|
|
1051
1189
|
const processedData = this.processDataForStorage(data);
|
|
1052
1190
|
this.componentData = { ...this.componentData, ...processedData };
|
|
1053
1191
|
}
|
|
1054
|
-
/**
|
|
1055
|
-
* Get text response
|
|
1056
|
-
*/
|
|
1057
|
-
getTextResponse() {
|
|
1058
|
-
return this.textResponse;
|
|
1059
|
-
}
|
|
1060
1192
|
/**
|
|
1061
1193
|
* Set or update text response
|
|
1062
1194
|
*/
|
|
@@ -1247,8 +1379,11 @@ var Thread = class {
|
|
|
1247
1379
|
const questionNum = index + 1;
|
|
1248
1380
|
const question = block.getUserQuestion();
|
|
1249
1381
|
const metadata = block.getComponentMetadata();
|
|
1250
|
-
|
|
1251
|
-
|
|
1382
|
+
const textResponse = block.getTextResponse();
|
|
1383
|
+
let assistantResponse = "";
|
|
1384
|
+
const hasComponent = metadata && Object.keys(metadata).length > 0 && metadata.type;
|
|
1385
|
+
const hasTextResponse = textResponse && textResponse.trim().length > 0;
|
|
1386
|
+
if (hasComponent) {
|
|
1252
1387
|
const parts = [];
|
|
1253
1388
|
if (metadata.type) {
|
|
1254
1389
|
parts.push(`Component Type: ${metadata.type}`);
|
|
@@ -1268,11 +1403,17 @@ var Thread = class {
|
|
|
1268
1403
|
const componentTypes = metadata.props.config.components.map((c) => c.type).join(", ");
|
|
1269
1404
|
parts.push(`Multi-component with: ${componentTypes}`);
|
|
1270
1405
|
}
|
|
1271
|
-
|
|
1406
|
+
assistantResponse = parts.join(", ");
|
|
1407
|
+
} else if (hasTextResponse) {
|
|
1408
|
+
assistantResponse = textResponse;
|
|
1409
|
+
} else {
|
|
1410
|
+
assistantResponse = "No response generated";
|
|
1272
1411
|
}
|
|
1273
|
-
contextLines.push(`
|
|
1274
|
-
|
|
1275
|
-
contextLines.push(
|
|
1412
|
+
contextLines.push(`User:
|
|
1413
|
+
${question}`);
|
|
1414
|
+
contextLines.push(`Assistant:
|
|
1415
|
+
${assistantResponse}`);
|
|
1416
|
+
contextLines.push("---");
|
|
1276
1417
|
});
|
|
1277
1418
|
return contextLines.join("\n").trim();
|
|
1278
1419
|
}
|
|
@@ -1448,7 +1589,7 @@ function sendDataResponse(id, collection, op, data, meta, sendMessage) {
|
|
|
1448
1589
|
}
|
|
1449
1590
|
|
|
1450
1591
|
// src/bundle.ts
|
|
1451
|
-
import * as
|
|
1592
|
+
import * as fs2 from "fs";
|
|
1452
1593
|
import * as path from "path";
|
|
1453
1594
|
function getBundleDir(configDir) {
|
|
1454
1595
|
const bundleDir = configDir || process.env.SA_BUNDLE_DIR;
|
|
@@ -1461,16 +1602,16 @@ function getBundleDir(configDir) {
|
|
|
1461
1602
|
}
|
|
1462
1603
|
function getJS(bundleDir) {
|
|
1463
1604
|
try {
|
|
1464
|
-
if (!
|
|
1605
|
+
if (!fs2.existsSync(bundleDir)) {
|
|
1465
1606
|
throw new Error(`Bundle directory does not exist: ${bundleDir}`);
|
|
1466
1607
|
}
|
|
1467
|
-
const stats =
|
|
1608
|
+
const stats = fs2.statSync(bundleDir);
|
|
1468
1609
|
if (!stats.isDirectory()) {
|
|
1469
1610
|
throw new Error(`Bundle path is not a directory: ${bundleDir}`);
|
|
1470
1611
|
}
|
|
1471
1612
|
let files;
|
|
1472
1613
|
try {
|
|
1473
|
-
files =
|
|
1614
|
+
files = fs2.readdirSync(bundleDir);
|
|
1474
1615
|
} catch (error) {
|
|
1475
1616
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1476
1617
|
throw new Error(`Failed to read bundle directory: ${errorMessage}`);
|
|
@@ -1485,7 +1626,7 @@ function getJS(bundleDir) {
|
|
|
1485
1626
|
const filePath = path.join(bundleDir, indexFile);
|
|
1486
1627
|
logger.info(`Loading bundle from ${filePath}`);
|
|
1487
1628
|
try {
|
|
1488
|
-
return
|
|
1629
|
+
return fs2.readFileSync(filePath, "utf8");
|
|
1489
1630
|
} catch (error) {
|
|
1490
1631
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1491
1632
|
throw new Error(`Failed to read bundle file: ${errorMessage}`);
|
|
@@ -1891,94 +2032,12 @@ function sendDataResponse3(id, res, sendMessage, clientId) {
|
|
|
1891
2032
|
// src/userResponse/groq.ts
|
|
1892
2033
|
var import_dotenv = __toESM(require_main());
|
|
1893
2034
|
|
|
1894
|
-
// src/userResponse/
|
|
1895
|
-
|
|
1896
|
-
if (!query || query.trim().length === 0) {
|
|
1897
|
-
return query;
|
|
1898
|
-
}
|
|
1899
|
-
let modifiedQuery = query.replace(/\bSELECT\s+TOP\s+(\d+)\b/gi, "SELECT");
|
|
1900
|
-
if (modifiedQuery !== query) {
|
|
1901
|
-
console.warn(`\u26A0\uFE0F Query had TOP syntax. Converting to LIMIT for Snowflake compatibility.`);
|
|
1902
|
-
}
|
|
1903
|
-
return modifiedQuery;
|
|
1904
|
-
}
|
|
1905
|
-
function ensureQueryLimit(query, defaultLimit = 50) {
|
|
1906
|
-
if (!query || query.trim().length === 0) {
|
|
1907
|
-
return query;
|
|
1908
|
-
}
|
|
1909
|
-
let trimmedQuery = query.trim();
|
|
1910
|
-
const isSelectQuery = /^\s*SELECT\b/i.test(trimmedQuery) || /^\s*WITH\b.*\bSELECT\b/is.test(trimmedQuery);
|
|
1911
|
-
if (!isSelectQuery) {
|
|
1912
|
-
return query;
|
|
1913
|
-
}
|
|
1914
|
-
trimmedQuery = convertTopToLimit(trimmedQuery);
|
|
1915
|
-
const hadSemicolon = trimmedQuery.endsWith(";");
|
|
1916
|
-
if (hadSemicolon) {
|
|
1917
|
-
trimmedQuery = trimmedQuery.slice(0, -1).trim();
|
|
1918
|
-
}
|
|
1919
|
-
const limitMatches = trimmedQuery.match(/\bLIMIT\s+\d+\b/gi);
|
|
1920
|
-
if (limitMatches && limitMatches.length > 0) {
|
|
1921
|
-
if (limitMatches.length > 1) {
|
|
1922
|
-
console.warn(`\u26A0\uFE0F Query had ${limitMatches.length} LIMIT clauses. Removing duplicates...`);
|
|
1923
|
-
trimmedQuery = trimmedQuery.replace(/\s*\bLIMIT\s+\d+\b/gi, "").trim();
|
|
1924
|
-
} else {
|
|
1925
|
-
if (hadSemicolon) {
|
|
1926
|
-
trimmedQuery += ";";
|
|
1927
|
-
}
|
|
1928
|
-
return trimmedQuery;
|
|
1929
|
-
}
|
|
1930
|
-
}
|
|
1931
|
-
trimmedQuery = `${trimmedQuery} LIMIT ${defaultLimit}`;
|
|
1932
|
-
if (hadSemicolon) {
|
|
1933
|
-
trimmedQuery += ";";
|
|
1934
|
-
}
|
|
1935
|
-
return trimmedQuery;
|
|
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
|
-
}
|
|
2035
|
+
// src/userResponse/base-llm.ts
|
|
2036
|
+
init_utils();
|
|
1978
2037
|
|
|
1979
2038
|
// src/userResponse/schema.ts
|
|
1980
2039
|
import path2 from "path";
|
|
1981
|
-
import
|
|
2040
|
+
import fs3 from "fs";
|
|
1982
2041
|
var Schema = class {
|
|
1983
2042
|
constructor(schemaFilePath) {
|
|
1984
2043
|
this.cachedSchema = null;
|
|
@@ -1992,11 +2051,11 @@ var Schema = class {
|
|
|
1992
2051
|
logger.info(`SCHEMA_FILE_PATH: ${this.schemaFilePath}`);
|
|
1993
2052
|
try {
|
|
1994
2053
|
const dir = path2.dirname(this.schemaFilePath);
|
|
1995
|
-
if (!
|
|
2054
|
+
if (!fs3.existsSync(dir)) {
|
|
1996
2055
|
logger.info(`Creating directory structure: ${dir}`);
|
|
1997
|
-
|
|
2056
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
1998
2057
|
}
|
|
1999
|
-
if (!
|
|
2058
|
+
if (!fs3.existsSync(this.schemaFilePath)) {
|
|
2000
2059
|
logger.info(`Schema file does not exist at ${this.schemaFilePath}, creating with empty schema`);
|
|
2001
2060
|
const initialSchema = {
|
|
2002
2061
|
database: "",
|
|
@@ -2005,11 +2064,11 @@ var Schema = class {
|
|
|
2005
2064
|
tables: [],
|
|
2006
2065
|
relationships: []
|
|
2007
2066
|
};
|
|
2008
|
-
|
|
2067
|
+
fs3.writeFileSync(this.schemaFilePath, JSON.stringify(initialSchema, null, 4));
|
|
2009
2068
|
this.cachedSchema = initialSchema;
|
|
2010
2069
|
return initialSchema;
|
|
2011
2070
|
}
|
|
2012
|
-
const fileContent =
|
|
2071
|
+
const fileContent = fs3.readFileSync(this.schemaFilePath, "utf-8");
|
|
2013
2072
|
const schema2 = JSON.parse(fileContent);
|
|
2014
2073
|
this.cachedSchema = schema2;
|
|
2015
2074
|
return schema2;
|
|
@@ -2110,7 +2169,7 @@ var Schema = class {
|
|
|
2110
2169
|
var schema = new Schema();
|
|
2111
2170
|
|
|
2112
2171
|
// src/userResponse/prompt-loader.ts
|
|
2113
|
-
import
|
|
2172
|
+
import fs4 from "fs";
|
|
2114
2173
|
import path3 from "path";
|
|
2115
2174
|
var PromptLoader = class {
|
|
2116
2175
|
constructor(config) {
|
|
@@ -2138,7 +2197,8 @@ var PromptLoader = class {
|
|
|
2138
2197
|
"mutli-component",
|
|
2139
2198
|
"actions",
|
|
2140
2199
|
"container-metadata",
|
|
2141
|
-
"text-response"
|
|
2200
|
+
"text-response",
|
|
2201
|
+
"match-text-components"
|
|
2142
2202
|
];
|
|
2143
2203
|
for (const promptType of promptTypes) {
|
|
2144
2204
|
try {
|
|
@@ -2163,9 +2223,9 @@ var PromptLoader = class {
|
|
|
2163
2223
|
try {
|
|
2164
2224
|
const systemPath = path3.join(dir, promptName, "system.md");
|
|
2165
2225
|
const userPath = path3.join(dir, promptName, "user.md");
|
|
2166
|
-
if (
|
|
2167
|
-
const system =
|
|
2168
|
-
const user =
|
|
2226
|
+
if (fs4.existsSync(systemPath) && fs4.existsSync(userPath)) {
|
|
2227
|
+
const system = fs4.readFileSync(systemPath, "utf-8");
|
|
2228
|
+
const user = fs4.readFileSync(userPath, "utf-8");
|
|
2169
2229
|
logger.debug(`Loaded prompt '${promptName}' from ${dir}`);
|
|
2170
2230
|
return { system, user };
|
|
2171
2231
|
}
|
|
@@ -2287,6 +2347,14 @@ var LLM = class {
|
|
|
2287
2347
|
throw new Error(`Unsupported provider: ${provider}. Use "anthropic" or "groq"`);
|
|
2288
2348
|
}
|
|
2289
2349
|
}
|
|
2350
|
+
/* Stream response with tool calling support (Anthropic only for now) */
|
|
2351
|
+
static async streamWithTools(messages, tools, toolHandler, options = {}, maxIterations = 3) {
|
|
2352
|
+
const [provider, modelName] = this._parseModel(options.model);
|
|
2353
|
+
if (provider !== "anthropic") {
|
|
2354
|
+
throw new Error(`Tool calling is only supported for Anthropic models`);
|
|
2355
|
+
}
|
|
2356
|
+
return this._anthropicStreamWithTools(messages, tools, toolHandler, modelName, options, maxIterations);
|
|
2357
|
+
}
|
|
2290
2358
|
// ============================================================
|
|
2291
2359
|
// PRIVATE HELPER METHODS
|
|
2292
2360
|
// ============================================================
|
|
@@ -2364,6 +2432,86 @@ var LLM = class {
|
|
|
2364
2432
|
}
|
|
2365
2433
|
return fullText;
|
|
2366
2434
|
}
|
|
2435
|
+
static async _anthropicStreamWithTools(messages, tools, toolHandler, modelName, options, maxIterations) {
|
|
2436
|
+
const apiKey = options.apiKey || process.env.ANTHROPIC_API_KEY || "";
|
|
2437
|
+
const client = new Anthropic({
|
|
2438
|
+
apiKey
|
|
2439
|
+
});
|
|
2440
|
+
const conversationMessages = [{
|
|
2441
|
+
role: "user",
|
|
2442
|
+
content: messages.user
|
|
2443
|
+
}];
|
|
2444
|
+
let iterations = 0;
|
|
2445
|
+
let finalText = "";
|
|
2446
|
+
while (iterations < maxIterations) {
|
|
2447
|
+
iterations++;
|
|
2448
|
+
const response = await client.messages.create({
|
|
2449
|
+
model: modelName,
|
|
2450
|
+
max_tokens: options.maxTokens || 4e3,
|
|
2451
|
+
temperature: options.temperature,
|
|
2452
|
+
system: messages.sys,
|
|
2453
|
+
messages: conversationMessages,
|
|
2454
|
+
tools
|
|
2455
|
+
});
|
|
2456
|
+
if (response.stop_reason === "end_turn") {
|
|
2457
|
+
const textBlock = response.content.find((block) => block.type === "text");
|
|
2458
|
+
if (textBlock && textBlock.type === "text") {
|
|
2459
|
+
finalText = textBlock.text;
|
|
2460
|
+
if (options.partial) {
|
|
2461
|
+
options.partial(finalText);
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
break;
|
|
2465
|
+
}
|
|
2466
|
+
if (response.stop_reason === "tool_use") {
|
|
2467
|
+
const toolUses = response.content.filter((block) => block.type === "tool_use");
|
|
2468
|
+
if (toolUses.length === 0) {
|
|
2469
|
+
break;
|
|
2470
|
+
}
|
|
2471
|
+
conversationMessages.push({
|
|
2472
|
+
role: "assistant",
|
|
2473
|
+
content: response.content
|
|
2474
|
+
});
|
|
2475
|
+
const toolResults = {
|
|
2476
|
+
role: "user",
|
|
2477
|
+
content: []
|
|
2478
|
+
};
|
|
2479
|
+
for (const toolUse of toolUses) {
|
|
2480
|
+
if (toolUse.type === "tool_use") {
|
|
2481
|
+
try {
|
|
2482
|
+
const result = await toolHandler(toolUse.name, toolUse.input);
|
|
2483
|
+
toolResults.content.push({
|
|
2484
|
+
type: "tool_result",
|
|
2485
|
+
tool_use_id: toolUse.id,
|
|
2486
|
+
content: typeof result === "string" ? result : JSON.stringify(result)
|
|
2487
|
+
});
|
|
2488
|
+
} catch (error) {
|
|
2489
|
+
toolResults.content.push({
|
|
2490
|
+
type: "tool_result",
|
|
2491
|
+
tool_use_id: toolUse.id,
|
|
2492
|
+
content: error instanceof Error ? error.message : String(error),
|
|
2493
|
+
is_error: true
|
|
2494
|
+
});
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
conversationMessages.push(toolResults);
|
|
2499
|
+
} else {
|
|
2500
|
+
const textBlock = response.content.find((block) => block.type === "text");
|
|
2501
|
+
if (textBlock && textBlock.type === "text") {
|
|
2502
|
+
finalText = textBlock.text;
|
|
2503
|
+
if (options.partial) {
|
|
2504
|
+
options.partial(finalText);
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
break;
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
if (iterations >= maxIterations) {
|
|
2511
|
+
throw new Error(`Max iterations (${maxIterations}) reached in tool calling loop`);
|
|
2512
|
+
}
|
|
2513
|
+
return finalText;
|
|
2514
|
+
}
|
|
2367
2515
|
// ============================================================
|
|
2368
2516
|
// GROQ IMPLEMENTATION
|
|
2369
2517
|
// ============================================================
|
|
@@ -2976,62 +3124,460 @@ var BaseLLM = class {
|
|
|
2976
3124
|
throw error;
|
|
2977
3125
|
}
|
|
2978
3126
|
}
|
|
3127
|
+
/**
|
|
3128
|
+
* Match components from text response suggestions
|
|
3129
|
+
* Takes a text response with component suggestions (c1:type format) and matches with available components
|
|
3130
|
+
* @param textResponse - The text response containing component suggestions
|
|
3131
|
+
* @param components - List of available components
|
|
3132
|
+
* @param apiKey - Optional API key
|
|
3133
|
+
* @param logCollector - Optional log collector
|
|
3134
|
+
* @returns Object containing matched components, selected layout, and reasoning
|
|
3135
|
+
*/
|
|
3136
|
+
async matchComponentsFromTextResponse(textResponse, components, apiKey, logCollector) {
|
|
3137
|
+
try {
|
|
3138
|
+
logger.debug(`[${this.getProviderName()}] Starting component matching from text response`);
|
|
3139
|
+
let availableComponentsText = "No components available";
|
|
3140
|
+
if (components && components.length > 0) {
|
|
3141
|
+
availableComponentsText = components.map((comp, idx) => {
|
|
3142
|
+
const keywords = comp.keywords ? comp.keywords.join(", ") : "";
|
|
3143
|
+
const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
|
|
3144
|
+
return `${idx + 1}. ID: ${comp.id}
|
|
3145
|
+
Name: ${comp.name}
|
|
3146
|
+
Type: ${comp.type}
|
|
3147
|
+
Description: ${comp.description || "No description"}
|
|
3148
|
+
Keywords: ${keywords}
|
|
3149
|
+
Props Structure: ${propsPreview}`;
|
|
3150
|
+
}).join("\n\n");
|
|
3151
|
+
}
|
|
3152
|
+
const schemaDoc = schema.generateSchemaDocumentation();
|
|
3153
|
+
const prompts = await promptLoader.loadPrompts("match-text-components", {
|
|
3154
|
+
TEXT_RESPONSE: textResponse,
|
|
3155
|
+
AVAILABLE_COMPONENTS: availableComponentsText,
|
|
3156
|
+
SCHEMA_DOC: schemaDoc
|
|
3157
|
+
});
|
|
3158
|
+
logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
|
|
3159
|
+
logger.file("\n=============================\nmatch text components system prompt:", prompts.system);
|
|
3160
|
+
logCollector?.info("Matching components from text response...");
|
|
3161
|
+
const rawResponse = await LLM.stream(
|
|
3162
|
+
{
|
|
3163
|
+
sys: prompts.system,
|
|
3164
|
+
user: prompts.user
|
|
3165
|
+
},
|
|
3166
|
+
{
|
|
3167
|
+
model: this.model,
|
|
3168
|
+
maxTokens: 3e3,
|
|
3169
|
+
temperature: 0.2,
|
|
3170
|
+
apiKey: this.getApiKey(apiKey)
|
|
3171
|
+
},
|
|
3172
|
+
false
|
|
3173
|
+
// Don't parse as JSON yet, get raw response
|
|
3174
|
+
);
|
|
3175
|
+
logger.debug(`[${this.getProviderName()}] Raw component matching response length: ${rawResponse?.length || 0}`);
|
|
3176
|
+
logger.file(`[${this.getProviderName()}] Component matching raw response:`, rawResponse);
|
|
3177
|
+
let result;
|
|
3178
|
+
try {
|
|
3179
|
+
let cleanedResponse = rawResponse || "";
|
|
3180
|
+
cleanedResponse = cleanedResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
|
|
3181
|
+
const jsonMatch = cleanedResponse.match(/\{[\s\S]*\}/);
|
|
3182
|
+
if (jsonMatch) {
|
|
3183
|
+
cleanedResponse = jsonMatch[0];
|
|
3184
|
+
}
|
|
3185
|
+
result = JSON.parse(cleanedResponse);
|
|
3186
|
+
} catch (parseError) {
|
|
3187
|
+
logger.error(`[${this.getProviderName()}] Failed to parse component matching JSON response`);
|
|
3188
|
+
const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
|
|
3189
|
+
const posMatch = errorMsg.match(/position (\d+)/);
|
|
3190
|
+
const errorPos = posMatch ? parseInt(posMatch[1]) : -1;
|
|
3191
|
+
if (errorPos > 0 && rawResponse) {
|
|
3192
|
+
const start = Math.max(0, errorPos - 200);
|
|
3193
|
+
const end = Math.min(rawResponse.length, errorPos + 200);
|
|
3194
|
+
logger.debug(`[${this.getProviderName()}] Error context (position ${errorPos}):`);
|
|
3195
|
+
logger.debug(rawResponse.substring(start, end));
|
|
3196
|
+
logger.debug(" ".repeat(Math.min(200, errorPos - start)) + "^--- Error here");
|
|
3197
|
+
}
|
|
3198
|
+
logger.debug(`[${this.getProviderName()}] Raw response (first 2000 chars):`, rawResponse?.substring(0, 2e3));
|
|
3199
|
+
logger.debug(`[${this.getProviderName()}] Parse error:`, parseError);
|
|
3200
|
+
logCollector?.error(`Failed to parse component matching response: ${errorMsg}`);
|
|
3201
|
+
try {
|
|
3202
|
+
logger.info(`[${this.getProviderName()}] Attempting aggressive JSON cleanup...`);
|
|
3203
|
+
let aggressive = rawResponse || "";
|
|
3204
|
+
aggressive = aggressive.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
|
|
3205
|
+
const match = aggressive.match(/\{[\s\S]*\}/);
|
|
3206
|
+
if (match) {
|
|
3207
|
+
aggressive = match[0];
|
|
3208
|
+
}
|
|
3209
|
+
aggressive = aggressive.replace(/,(\s*[}\]])/g, "$1");
|
|
3210
|
+
result = JSON.parse(aggressive);
|
|
3211
|
+
logger.info(`[${this.getProviderName()}] Aggressive cleanup succeeded!`);
|
|
3212
|
+
} catch (secondError) {
|
|
3213
|
+
logger.error(`[${this.getProviderName()}] Aggressive cleanup also failed`);
|
|
3214
|
+
return {
|
|
3215
|
+
components: [],
|
|
3216
|
+
selectedLayout: "MultiComponentContainer",
|
|
3217
|
+
selectedLayoutId: "",
|
|
3218
|
+
selectedLayoutComponent: null,
|
|
3219
|
+
layoutReasoning: "No layout selected"
|
|
3220
|
+
};
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
const matchedComponents = result.matchedComponents || [];
|
|
3224
|
+
const selectedLayout = result.selectedLayout || "MultiComponentContainer";
|
|
3225
|
+
const selectedLayoutId = result.selectedLayoutId || "";
|
|
3226
|
+
const layoutReasoning = result.layoutReasoning || "No layout reasoning provided";
|
|
3227
|
+
let selectedLayoutComponent = null;
|
|
3228
|
+
if (selectedLayoutId) {
|
|
3229
|
+
selectedLayoutComponent = components.find((c) => c.id === selectedLayoutId) || null;
|
|
3230
|
+
if (!selectedLayoutComponent) {
|
|
3231
|
+
logger.warn(`[${this.getProviderName()}] Layout component ${selectedLayoutId} not found in available components`);
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
logger.info(`[${this.getProviderName()}] Matched ${matchedComponents.length} components from text response`);
|
|
3235
|
+
logger.info(`[${this.getProviderName()}] Selected layout: ${selectedLayout} (ID: ${selectedLayoutId})`);
|
|
3236
|
+
logger.info(`[${this.getProviderName()}] Layout reasoning: ${layoutReasoning}`);
|
|
3237
|
+
if (matchedComponents.length > 0) {
|
|
3238
|
+
logCollector?.info(`Matched ${matchedComponents.length} components for visualization using ${selectedLayout}`);
|
|
3239
|
+
logCollector?.info(`Layout reasoning: ${layoutReasoning}`);
|
|
3240
|
+
matchedComponents.forEach((comp, idx) => {
|
|
3241
|
+
logCollector?.info(` ${idx + 1}. ${comp.componentName} (${comp.componentType}): ${comp.reasoning}`);
|
|
3242
|
+
if (comp.props?.query) {
|
|
3243
|
+
logCollector?.logQuery(
|
|
3244
|
+
`Component ${idx + 1} query`,
|
|
3245
|
+
comp.props.query,
|
|
3246
|
+
{ componentName: comp.componentName, title: comp.props.title }
|
|
3247
|
+
);
|
|
3248
|
+
}
|
|
3249
|
+
});
|
|
3250
|
+
}
|
|
3251
|
+
const finalComponents = matchedComponents.map((mc) => {
|
|
3252
|
+
const originalComponent = components.find((c) => c.id === mc.componentId);
|
|
3253
|
+
if (!originalComponent) {
|
|
3254
|
+
logger.warn(`[${this.getProviderName()}] Component ${mc.componentId} not found in available components`);
|
|
3255
|
+
return null;
|
|
3256
|
+
}
|
|
3257
|
+
return {
|
|
3258
|
+
...originalComponent,
|
|
3259
|
+
props: {
|
|
3260
|
+
...originalComponent.props,
|
|
3261
|
+
...mc.props
|
|
3262
|
+
}
|
|
3263
|
+
};
|
|
3264
|
+
}).filter(Boolean);
|
|
3265
|
+
return {
|
|
3266
|
+
components: finalComponents,
|
|
3267
|
+
selectedLayout,
|
|
3268
|
+
selectedLayoutId,
|
|
3269
|
+
selectedLayoutComponent,
|
|
3270
|
+
layoutReasoning
|
|
3271
|
+
};
|
|
3272
|
+
} catch (error) {
|
|
3273
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3274
|
+
logger.error(`[${this.getProviderName()}] Error matching components from text response: ${errorMsg}`);
|
|
3275
|
+
logger.debug(`[${this.getProviderName()}] Component matching error details:`, error);
|
|
3276
|
+
logCollector?.error(`Error matching components: ${errorMsg}`);
|
|
3277
|
+
return {
|
|
3278
|
+
components: [],
|
|
3279
|
+
selectedLayout: "MultiComponentContainer",
|
|
3280
|
+
selectedLayoutId: "",
|
|
3281
|
+
selectedLayoutComponent: null,
|
|
3282
|
+
layoutReasoning: "Error occurred during component matching"
|
|
3283
|
+
};
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
2979
3286
|
/**
|
|
2980
3287
|
* Generate text-based response for user question
|
|
2981
3288
|
* This provides conversational text responses instead of component generation
|
|
3289
|
+
* Supports tool calling for query execution with automatic retry on errors (max 3 attempts)
|
|
3290
|
+
* After generating text response, if components are provided, matches suggested components
|
|
3291
|
+
* @param streamCallback - Optional callback function to receive text chunks as they stream
|
|
3292
|
+
* @param collections - Collection registry for executing database queries via database.execute
|
|
3293
|
+
* @param components - Optional list of available components for matching suggestions
|
|
2982
3294
|
*/
|
|
2983
|
-
async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory) {
|
|
3295
|
+
async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory, streamCallback, collections, components) {
|
|
2984
3296
|
const errors = [];
|
|
2985
3297
|
logger.debug(`[${this.getProviderName()}] Starting text response generation`);
|
|
2986
3298
|
logger.debug(`[${this.getProviderName()}] User prompt: "${userPrompt.substring(0, 50)}..."`);
|
|
2987
3299
|
try {
|
|
3300
|
+
const schemaDoc = schema.generateSchemaDocumentation();
|
|
2988
3301
|
const prompts = await promptLoader.loadPrompts("text-response", {
|
|
2989
3302
|
USER_PROMPT: userPrompt,
|
|
2990
|
-
CONVERSATION_HISTORY: conversationHistory || "No previous conversation"
|
|
3303
|
+
CONVERSATION_HISTORY: conversationHistory || "No previous conversation",
|
|
3304
|
+
SCHEMA_DOC: schemaDoc
|
|
2991
3305
|
});
|
|
2992
|
-
logger.
|
|
3306
|
+
logger.file("\n=============================\nsystem prompt:", prompts.system);
|
|
3307
|
+
logger.file("\n=============================\nuser prompt:", prompts.user);
|
|
3308
|
+
logger.debug(`[${this.getProviderName()}] Loaded text-response prompts with schema`);
|
|
2993
3309
|
logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
|
|
2994
|
-
logCollector?.info("Generating text response...");
|
|
2995
|
-
const
|
|
3310
|
+
logCollector?.info("Generating text response with query execution capability...");
|
|
3311
|
+
const tools = [{
|
|
3312
|
+
name: "execute_query",
|
|
3313
|
+
description: "Executes a SQL query against the database and returns the results. Use this when the user asks for data. If the query fails, you will receive the error and can retry with a corrected query.",
|
|
3314
|
+
input_schema: {
|
|
3315
|
+
type: "object",
|
|
3316
|
+
properties: {
|
|
3317
|
+
query: {
|
|
3318
|
+
type: "string",
|
|
3319
|
+
description: "The SQL query to execute. Must be valid SQL syntax using table and column names from the schema."
|
|
3320
|
+
},
|
|
3321
|
+
reasoning: {
|
|
3322
|
+
type: "string",
|
|
3323
|
+
description: "Brief explanation of what this query does and why it answers the user's question."
|
|
3324
|
+
}
|
|
3325
|
+
},
|
|
3326
|
+
required: ["query"]
|
|
3327
|
+
}
|
|
3328
|
+
}];
|
|
3329
|
+
const queryAttempts = /* @__PURE__ */ new Map();
|
|
3330
|
+
const MAX_QUERY_ATTEMPTS = 6;
|
|
3331
|
+
let maxAttemptsReached = false;
|
|
3332
|
+
let fullStreamedText = "";
|
|
3333
|
+
const wrappedStreamCallback = streamCallback ? (chunk) => {
|
|
3334
|
+
fullStreamedText += chunk;
|
|
3335
|
+
streamCallback(chunk);
|
|
3336
|
+
} : void 0;
|
|
3337
|
+
const toolHandler = async (toolName, toolInput) => {
|
|
3338
|
+
if (toolName === "execute_query") {
|
|
3339
|
+
let query = toolInput.query;
|
|
3340
|
+
const reasoning = toolInput.reasoning;
|
|
3341
|
+
const { ensureQueryLimit: ensureQueryLimit2 } = await Promise.resolve().then(() => (init_utils(), utils_exports));
|
|
3342
|
+
query = ensureQueryLimit2(query, 32, 32);
|
|
3343
|
+
const queryKey = query.toLowerCase().replace(/\s+/g, " ").trim();
|
|
3344
|
+
const attempts = (queryAttempts.get(queryKey) || 0) + 1;
|
|
3345
|
+
queryAttempts.set(queryKey, attempts);
|
|
3346
|
+
logger.info(`[${this.getProviderName()}] Executing query (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${query.substring(0, 100)}...`);
|
|
3347
|
+
if (reasoning) {
|
|
3348
|
+
logCollector?.info(`Query reasoning: ${reasoning}`);
|
|
3349
|
+
}
|
|
3350
|
+
if (attempts > MAX_QUERY_ATTEMPTS) {
|
|
3351
|
+
const errorMsg = `Maximum query attempts (${MAX_QUERY_ATTEMPTS}) reached. Unable to generate a valid query for your question.`;
|
|
3352
|
+
logger.error(`[${this.getProviderName()}] ${errorMsg}`);
|
|
3353
|
+
logCollector?.error(errorMsg);
|
|
3354
|
+
maxAttemptsReached = true;
|
|
3355
|
+
if (wrappedStreamCallback) {
|
|
3356
|
+
wrappedStreamCallback(`
|
|
3357
|
+
|
|
3358
|
+
\u274C ${errorMsg}
|
|
3359
|
+
|
|
3360
|
+
Please try rephrasing your question or simplifying your request.
|
|
3361
|
+
|
|
3362
|
+
`);
|
|
3363
|
+
}
|
|
3364
|
+
throw new Error(errorMsg);
|
|
3365
|
+
}
|
|
3366
|
+
try {
|
|
3367
|
+
if (wrappedStreamCallback) {
|
|
3368
|
+
if (attempts === 1) {
|
|
3369
|
+
wrappedStreamCallback(`
|
|
3370
|
+
|
|
3371
|
+
\u{1F50D} **Analyzing your question...**
|
|
3372
|
+
|
|
3373
|
+
`);
|
|
3374
|
+
if (reasoning) {
|
|
3375
|
+
wrappedStreamCallback(`\u{1F4AD} ${reasoning}
|
|
3376
|
+
|
|
3377
|
+
`);
|
|
3378
|
+
}
|
|
3379
|
+
wrappedStreamCallback(`\u{1F4DD} **Generated SQL Query:**
|
|
3380
|
+
\`\`\`sql
|
|
3381
|
+
${query}
|
|
3382
|
+
\`\`\`
|
|
3383
|
+
|
|
3384
|
+
`);
|
|
3385
|
+
wrappedStreamCallback(`\u26A1 **Executing query...**
|
|
3386
|
+
|
|
3387
|
+
`);
|
|
3388
|
+
} else {
|
|
3389
|
+
wrappedStreamCallback(`
|
|
3390
|
+
|
|
3391
|
+
\u{1F504} **Retrying with corrected query (attempt ${attempts}/${MAX_QUERY_ATTEMPTS})...**
|
|
3392
|
+
|
|
3393
|
+
`);
|
|
3394
|
+
if (reasoning) {
|
|
3395
|
+
wrappedStreamCallback(`\u{1F4AD} ${reasoning}
|
|
3396
|
+
|
|
3397
|
+
`);
|
|
3398
|
+
}
|
|
3399
|
+
wrappedStreamCallback(`\u{1F4DD} **Corrected SQL Query:**
|
|
3400
|
+
\`\`\`sql
|
|
3401
|
+
${query}
|
|
3402
|
+
\`\`\`
|
|
3403
|
+
|
|
3404
|
+
`);
|
|
3405
|
+
wrappedStreamCallback(`\u26A1 **Executing query...**
|
|
3406
|
+
|
|
3407
|
+
`);
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
logCollector?.logQuery(
|
|
3411
|
+
`Executing SQL query (attempt ${attempts})`,
|
|
3412
|
+
query,
|
|
3413
|
+
{ reasoning, attempt: attempts }
|
|
3414
|
+
);
|
|
3415
|
+
if (!collections || !collections["database"] || !collections["database"]["execute"]) {
|
|
3416
|
+
throw new Error("Database collection not registered. Please register database.execute collection to execute queries.");
|
|
3417
|
+
}
|
|
3418
|
+
const result2 = await collections["database"]["execute"]({ sql: query });
|
|
3419
|
+
const data = result2?.data || result2;
|
|
3420
|
+
const rowCount = result2?.count ?? (Array.isArray(data) ? data.length : "N/A");
|
|
3421
|
+
logger.info(`[${this.getProviderName()}] Query executed successfully, rows returned: ${rowCount}`);
|
|
3422
|
+
logCollector?.info(`Query successful, returned ${rowCount} rows`);
|
|
3423
|
+
if (wrappedStreamCallback) {
|
|
3424
|
+
wrappedStreamCallback(`\u2705 **Query executed successfully!**
|
|
3425
|
+
|
|
3426
|
+
`);
|
|
3427
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
3428
|
+
const firstRow = data[0];
|
|
3429
|
+
const columns = Object.keys(firstRow);
|
|
3430
|
+
if (data.length === 1 && columns.length === 1) {
|
|
3431
|
+
const value = firstRow[columns[0]];
|
|
3432
|
+
wrappedStreamCallback(`**Result:** ${value}
|
|
3433
|
+
|
|
3434
|
+
`);
|
|
3435
|
+
} else if (data.length > 0) {
|
|
3436
|
+
wrappedStreamCallback(`**Retrieved ${rowCount} rows**
|
|
3437
|
+
|
|
3438
|
+
`);
|
|
3439
|
+
wrappedStreamCallback(`<DataTable>${JSON.stringify(data)}</DataTable>
|
|
3440
|
+
|
|
3441
|
+
`);
|
|
3442
|
+
}
|
|
3443
|
+
} else if (Array.isArray(data) && data.length === 0) {
|
|
3444
|
+
wrappedStreamCallback(`**No rows returned.**
|
|
3445
|
+
|
|
3446
|
+
`);
|
|
3447
|
+
}
|
|
3448
|
+
wrappedStreamCallback(`\u{1F4CA} **Analyzing results...**
|
|
3449
|
+
|
|
3450
|
+
`);
|
|
3451
|
+
}
|
|
3452
|
+
return JSON.stringify(data, null, 2);
|
|
3453
|
+
} catch (error) {
|
|
3454
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3455
|
+
logger.error(`[${this.getProviderName()}] Query execution failed (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${errorMsg}`);
|
|
3456
|
+
logCollector?.error(`Query failed (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${errorMsg}`);
|
|
3457
|
+
if (wrappedStreamCallback) {
|
|
3458
|
+
wrappedStreamCallback(`\u274C **Query execution failed:**
|
|
3459
|
+
\`\`\`
|
|
3460
|
+
${errorMsg}
|
|
3461
|
+
\`\`\`
|
|
3462
|
+
|
|
3463
|
+
`);
|
|
3464
|
+
if (attempts < MAX_QUERY_ATTEMPTS) {
|
|
3465
|
+
wrappedStreamCallback(`\u{1F527} **Generating corrected query...**
|
|
3466
|
+
|
|
3467
|
+
`);
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
throw new Error(`Query execution failed: ${errorMsg}`);
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
throw new Error(`Unknown tool: ${toolName}`);
|
|
3474
|
+
};
|
|
3475
|
+
const result = await LLM.streamWithTools(
|
|
2996
3476
|
{
|
|
2997
3477
|
sys: prompts.system,
|
|
2998
3478
|
user: prompts.user
|
|
2999
3479
|
},
|
|
3480
|
+
tools,
|
|
3481
|
+
toolHandler,
|
|
3000
3482
|
{
|
|
3001
3483
|
model: this.model,
|
|
3002
|
-
maxTokens:
|
|
3484
|
+
maxTokens: 4e3,
|
|
3003
3485
|
temperature: 0.7,
|
|
3004
|
-
apiKey: this.getApiKey(apiKey)
|
|
3486
|
+
apiKey: this.getApiKey(apiKey),
|
|
3487
|
+
partial: wrappedStreamCallback
|
|
3488
|
+
// Pass the wrapped streaming callback to LLM
|
|
3005
3489
|
},
|
|
3006
|
-
|
|
3007
|
-
//
|
|
3490
|
+
10
|
|
3491
|
+
// max iterations: allows for 6 retries + final response + buffer
|
|
3008
3492
|
);
|
|
3009
|
-
logger.info(`[${this.getProviderName()}] Text response
|
|
3010
|
-
|
|
3011
|
-
|
|
3493
|
+
logger.info(`[${this.getProviderName()}] Text response stream completed`);
|
|
3494
|
+
const textResponse = fullStreamedText || result || "I apologize, but I was unable to generate a response.";
|
|
3495
|
+
if (maxAttemptsReached) {
|
|
3496
|
+
logger.warn(`[${this.getProviderName()}] Max query attempts reached, returning failure response`);
|
|
3497
|
+
logCollector?.error("Failed to generate valid query after maximum attempts");
|
|
3498
|
+
return {
|
|
3499
|
+
success: false,
|
|
3500
|
+
errors: [`Maximum query attempts (${MAX_QUERY_ATTEMPTS}) reached. Unable to generate a valid query for your question.`],
|
|
3501
|
+
data: {
|
|
3502
|
+
text: textResponse,
|
|
3503
|
+
// Include the streamed text showing all attempts
|
|
3504
|
+
matchedComponents: [],
|
|
3505
|
+
method: `${this.getProviderName()}-text-response-max-attempts`
|
|
3506
|
+
}
|
|
3507
|
+
};
|
|
3508
|
+
}
|
|
3509
|
+
logCollector?.info(`Text response: ${textResponse.substring(0, 100)}${textResponse.length > 100 ? "..." : ""}`);
|
|
3012
3510
|
logCollector?.logExplanation(
|
|
3013
3511
|
"Text response generated",
|
|
3014
|
-
|
|
3512
|
+
"Generated plain text response with component suggestions",
|
|
3015
3513
|
{
|
|
3016
|
-
|
|
3017
|
-
confidence: result.confidence,
|
|
3018
|
-
textLength: result.text?.length || 0
|
|
3514
|
+
textLength: textResponse.length
|
|
3019
3515
|
}
|
|
3020
3516
|
);
|
|
3517
|
+
let matchedComponents = [];
|
|
3518
|
+
let selectedLayoutComponent = null;
|
|
3519
|
+
let layoutReasoning = "No layout selected";
|
|
3520
|
+
if (components && components.length > 0) {
|
|
3521
|
+
logger.info(`[${this.getProviderName()}] Matching components from text response...`);
|
|
3522
|
+
const matchResult = await this.matchComponentsFromTextResponse(
|
|
3523
|
+
textResponse,
|
|
3524
|
+
components,
|
|
3525
|
+
apiKey,
|
|
3526
|
+
logCollector
|
|
3527
|
+
);
|
|
3528
|
+
matchedComponents = matchResult.components;
|
|
3529
|
+
selectedLayoutComponent = matchResult.selectedLayoutComponent;
|
|
3530
|
+
layoutReasoning = matchResult.layoutReasoning;
|
|
3531
|
+
}
|
|
3532
|
+
let container_componet = null;
|
|
3533
|
+
if (matchedComponents.length > 0) {
|
|
3534
|
+
if (selectedLayoutComponent) {
|
|
3535
|
+
container_componet = {
|
|
3536
|
+
...selectedLayoutComponent,
|
|
3537
|
+
id: `${selectedLayoutComponent.id}_${Date.now()}`,
|
|
3538
|
+
description: layoutReasoning,
|
|
3539
|
+
props: {
|
|
3540
|
+
...selectedLayoutComponent.props,
|
|
3541
|
+
config: {
|
|
3542
|
+
...selectedLayoutComponent.props?.config || {},
|
|
3543
|
+
components: matchedComponents
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
};
|
|
3547
|
+
logger.info(`[${this.getProviderName()}] Created ${selectedLayoutComponent.name} (${selectedLayoutComponent.type}) container with ${matchedComponents.length} components`);
|
|
3548
|
+
logCollector?.info(`Created ${selectedLayoutComponent.name} with ${matchedComponents.length} components: ${layoutReasoning}`);
|
|
3549
|
+
} else {
|
|
3550
|
+
container_componet = {
|
|
3551
|
+
id: `multi_container_${Date.now()}`,
|
|
3552
|
+
name: "MultiComponentContainer",
|
|
3553
|
+
type: "Container",
|
|
3554
|
+
description: layoutReasoning,
|
|
3555
|
+
category: "dynamic",
|
|
3556
|
+
keywords: ["dashboard", "layout", "container"],
|
|
3557
|
+
props: {
|
|
3558
|
+
config: {
|
|
3559
|
+
components: matchedComponents
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
};
|
|
3563
|
+
logger.info(`[${this.getProviderName()}] Created fallback MultiComponentContainer with ${matchedComponents.length} components`);
|
|
3564
|
+
logCollector?.info(`Created MultiComponentContainer with ${matchedComponents.length} components: ${layoutReasoning}`);
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3021
3567
|
return {
|
|
3022
3568
|
success: true,
|
|
3023
3569
|
data: {
|
|
3024
|
-
text:
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3570
|
+
text: textResponse,
|
|
3571
|
+
matchedComponents,
|
|
3572
|
+
component: container_componet,
|
|
3573
|
+
layoutReasoning,
|
|
3574
|
+
method: `${this.getProviderName()}-text-response`
|
|
3028
3575
|
},
|
|
3029
3576
|
errors: []
|
|
3030
3577
|
};
|
|
3031
3578
|
} catch (error) {
|
|
3032
3579
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3033
3580
|
logger.error(`[${this.getProviderName()}] Error generating text response: ${errorMsg}`);
|
|
3034
|
-
logger.debug(`[${this.getProviderName()}] Text response generation error details:`, error);
|
|
3035
3581
|
logCollector?.error(`Error generating text response: ${errorMsg}`);
|
|
3036
3582
|
errors.push(errorMsg);
|
|
3037
3583
|
return {
|
|
@@ -3039,9 +3585,8 @@ var BaseLLM = class {
|
|
|
3039
3585
|
errors,
|
|
3040
3586
|
data: {
|
|
3041
3587
|
text: "I apologize, but I encountered an error while processing your question. Please try rephrasing or ask something else.",
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
reasoning: `Error: ${errorMsg}`
|
|
3588
|
+
matchedComponents: [],
|
|
3589
|
+
method: `${this.getProviderName()}-text-response-error`
|
|
3045
3590
|
}
|
|
3046
3591
|
};
|
|
3047
3592
|
}
|
|
@@ -3232,8 +3777,11 @@ var BaseLLM = class {
|
|
|
3232
3777
|
* Supports both component generation and text response modes
|
|
3233
3778
|
*
|
|
3234
3779
|
* @param responseMode - 'component' for component generation (default), 'text' for text responses
|
|
3780
|
+
* @param streamCallback - Optional callback function to receive text chunks as they stream (only for text mode)
|
|
3781
|
+
* @param collections - Collection registry for executing database queries (required for text mode)
|
|
3235
3782
|
*/
|
|
3236
|
-
async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") {
|
|
3783
|
+
async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) {
|
|
3784
|
+
const startTime = Date.now();
|
|
3237
3785
|
logger.info(`[${this.getProviderName()}] handleUserRequest called with responseMode: ${responseMode}`);
|
|
3238
3786
|
if (responseMode === "text") {
|
|
3239
3787
|
logger.info(`[${this.getProviderName()}] Using text response mode`);
|
|
@@ -3242,25 +3790,23 @@ var BaseLLM = class {
|
|
|
3242
3790
|
userPrompt,
|
|
3243
3791
|
apiKey,
|
|
3244
3792
|
logCollector,
|
|
3245
|
-
conversationHistory
|
|
3793
|
+
conversationHistory,
|
|
3794
|
+
streamCallback,
|
|
3795
|
+
collections,
|
|
3796
|
+
components
|
|
3246
3797
|
);
|
|
3247
3798
|
if (!textResponse.success) {
|
|
3799
|
+
const elapsedTime3 = Date.now() - startTime;
|
|
3248
3800
|
logger.error(`[${this.getProviderName()}] Text response generation failed`);
|
|
3801
|
+
logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime3}ms (${(elapsedTime3 / 1e3).toFixed(2)}s)`);
|
|
3802
|
+
logCollector?.info(`Total time taken: ${elapsedTime3}ms (${(elapsedTime3 / 1e3).toFixed(2)}s)`);
|
|
3249
3803
|
return textResponse;
|
|
3250
3804
|
}
|
|
3805
|
+
const elapsedTime2 = Date.now() - startTime;
|
|
3251
3806
|
logger.info(`[${this.getProviderName()}] Text response generated successfully`);
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
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
|
-
};
|
|
3807
|
+
logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
|
|
3808
|
+
logCollector?.info(`Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
|
|
3809
|
+
return textResponse;
|
|
3264
3810
|
}
|
|
3265
3811
|
const componentResponse = await this.generateComponentResponse(
|
|
3266
3812
|
userPrompt,
|
|
@@ -3270,24 +3816,17 @@ var BaseLLM = class {
|
|
|
3270
3816
|
conversationHistory
|
|
3271
3817
|
);
|
|
3272
3818
|
if (!componentResponse.success) {
|
|
3819
|
+
const elapsedTime2 = Date.now() - startTime;
|
|
3273
3820
|
logger.error(`[${this.getProviderName()}] Component response generation failed`);
|
|
3821
|
+
logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
|
|
3822
|
+
logCollector?.info(`Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
|
|
3274
3823
|
return componentResponse;
|
|
3275
3824
|
}
|
|
3825
|
+
const elapsedTime = Date.now() - startTime;
|
|
3276
3826
|
logger.info(`[${this.getProviderName()}] Component response generated successfully`);
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
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
|
-
};
|
|
3827
|
+
logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
|
|
3828
|
+
logCollector?.info(`Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
|
|
3829
|
+
return componentResponse;
|
|
3291
3830
|
}
|
|
3292
3831
|
/**
|
|
3293
3832
|
* Generate next questions that the user might ask based on the original prompt and generated component
|
|
@@ -3400,7 +3939,7 @@ function getLLMProviders() {
|
|
|
3400
3939
|
return DEFAULT_PROVIDERS;
|
|
3401
3940
|
}
|
|
3402
3941
|
}
|
|
3403
|
-
var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") => {
|
|
3942
|
+
var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) => {
|
|
3404
3943
|
logger.debug("[useAnthropicMethod] Initializing Anthropic Claude matching method");
|
|
3405
3944
|
logger.debug(`[useAnthropicMethod] Response mode: ${responseMode}`);
|
|
3406
3945
|
const msg = `Using Anthropic Claude ${responseMode === "text" ? "text response" : "matching"} method...`;
|
|
@@ -3412,11 +3951,11 @@ var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conver
|
|
|
3412
3951
|
return { success: false, errors: [emptyMsg] };
|
|
3413
3952
|
}
|
|
3414
3953
|
logger.debug(`[useAnthropicMethod] Processing with ${components.length} components`);
|
|
3415
|
-
const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode);
|
|
3954
|
+
const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
3416
3955
|
logger.info(`[useAnthropicMethod] Successfully generated ${responseMode} using Anthropic`);
|
|
3417
3956
|
return matchResult;
|
|
3418
3957
|
};
|
|
3419
|
-
var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") => {
|
|
3958
|
+
var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) => {
|
|
3420
3959
|
logger.debug("[useGroqMethod] Initializing Groq LLM matching method");
|
|
3421
3960
|
logger.debug(`[useGroqMethod] Response mode: ${responseMode}`);
|
|
3422
3961
|
const msg = `Using Groq LLM ${responseMode === "text" ? "text response" : "matching"} method...`;
|
|
@@ -3429,16 +3968,16 @@ var useGroqMethod = async (prompt, components, apiKey, logCollector, conversatio
|
|
|
3429
3968
|
return { success: false, errors: [emptyMsg] };
|
|
3430
3969
|
}
|
|
3431
3970
|
logger.debug(`[useGroqMethod] Processing with ${components.length} components`);
|
|
3432
|
-
const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode);
|
|
3971
|
+
const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
3433
3972
|
logger.info(`[useGroqMethod] Successfully generated ${responseMode} using Groq`);
|
|
3434
3973
|
return matchResult;
|
|
3435
3974
|
};
|
|
3436
3975
|
var getUserResponseFromCache = async (prompt) => {
|
|
3437
3976
|
return false;
|
|
3438
3977
|
};
|
|
3439
|
-
var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory) => {
|
|
3440
|
-
const responseMode = "component";
|
|
3978
|
+
var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) => {
|
|
3441
3979
|
logger.debug(`[get_user_response] Starting user response generation for prompt: "${prompt.substring(0, 50)}..."`);
|
|
3980
|
+
logger.debug(`[get_user_response] Response mode: ${responseMode}`);
|
|
3442
3981
|
logger.debug("[get_user_response] Checking cache for existing response");
|
|
3443
3982
|
const userResponse = await getUserResponseFromCache(prompt);
|
|
3444
3983
|
if (userResponse) {
|
|
@@ -3469,16 +4008,16 @@ var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey,
|
|
|
3469
4008
|
logCollector?.info(attemptMsg);
|
|
3470
4009
|
let result;
|
|
3471
4010
|
if (provider === "anthropic") {
|
|
3472
|
-
result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory, responseMode);
|
|
4011
|
+
result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
3473
4012
|
} else if (provider === "groq") {
|
|
3474
|
-
result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory, responseMode);
|
|
4013
|
+
result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
3475
4014
|
} else {
|
|
3476
4015
|
logger.warn(`[get_user_response] Unknown provider: ${provider} - skipping`);
|
|
3477
4016
|
errors.push(`Unknown provider: ${provider}`);
|
|
3478
4017
|
continue;
|
|
3479
4018
|
}
|
|
3480
4019
|
if (result.success) {
|
|
3481
|
-
const successMsg = `Success with provider: ${provider}
|
|
4020
|
+
const successMsg = `Success with provider: ${provider}`;
|
|
3482
4021
|
logger.info(`${successMsg}`);
|
|
3483
4022
|
logCollector?.info(successMsg);
|
|
3484
4023
|
return result;
|
|
@@ -3699,8 +4238,7 @@ var CONTEXT_CONFIG = {
|
|
|
3699
4238
|
};
|
|
3700
4239
|
|
|
3701
4240
|
// src/handlers/user-prompt-request.ts
|
|
3702
|
-
var
|
|
3703
|
-
var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders) => {
|
|
4241
|
+
var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections) => {
|
|
3704
4242
|
const errors = [];
|
|
3705
4243
|
logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
|
|
3706
4244
|
const parseResult = UserPromptRequestMessageSchema.safeParse(data);
|
|
@@ -3716,19 +4254,6 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3716
4254
|
const prompt = payload.prompt;
|
|
3717
4255
|
const SA_RUNTIME = payload.SA_RUNTIME;
|
|
3718
4256
|
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
4257
|
if (!SA_RUNTIME) {
|
|
3733
4258
|
errors.push("SA_RUNTIME is required");
|
|
3734
4259
|
}
|
|
@@ -3743,9 +4268,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3743
4268
|
if (!prompt) {
|
|
3744
4269
|
errors.push("Prompt not found");
|
|
3745
4270
|
}
|
|
3746
|
-
|
|
3747
|
-
errors.push("Components not found");
|
|
3748
|
-
}
|
|
4271
|
+
logger.debug(`[REQUEST ${id}] Full request details - uiBlockId: ${existingUiBlockId}, threadId: ${threadId}, prompt: ${prompt}`);
|
|
3749
4272
|
if (errors.length > 0) {
|
|
3750
4273
|
return { success: false, errors, id, wsId };
|
|
3751
4274
|
}
|
|
@@ -3759,8 +4282,44 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3759
4282
|
logCollector.info(`Starting user prompt request with ${components.length} components`);
|
|
3760
4283
|
const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
|
|
3761
4284
|
logger.info("conversationHistory", conversationHistory);
|
|
3762
|
-
const
|
|
3763
|
-
logger.info("
|
|
4285
|
+
const responseMode = payload.responseMode || "component";
|
|
4286
|
+
logger.info("responseMode", responseMode);
|
|
4287
|
+
let streamCallback;
|
|
4288
|
+
let accumulatedStreamResponse = "";
|
|
4289
|
+
if (responseMode === "text") {
|
|
4290
|
+
streamCallback = (chunk) => {
|
|
4291
|
+
accumulatedStreamResponse += chunk;
|
|
4292
|
+
logger.debug(`[STREAM] Sending chunk (${chunk.length} chars): "${chunk.substring(0, 20)}..."`);
|
|
4293
|
+
const streamMessage = {
|
|
4294
|
+
id: `stream_${existingUiBlockId}`,
|
|
4295
|
+
// Different ID pattern for streaming
|
|
4296
|
+
type: "USER_PROMPT_STREAM",
|
|
4297
|
+
from: { type: "data-agent" },
|
|
4298
|
+
to: {
|
|
4299
|
+
type: "runtime",
|
|
4300
|
+
id: wsId
|
|
4301
|
+
},
|
|
4302
|
+
payload: {
|
|
4303
|
+
uiBlockId: existingUiBlockId,
|
|
4304
|
+
chunk
|
|
4305
|
+
}
|
|
4306
|
+
};
|
|
4307
|
+
sendMessage(streamMessage);
|
|
4308
|
+
logger.debug(`[STREAM] Chunk sent to wsId: ${wsId}`);
|
|
4309
|
+
};
|
|
4310
|
+
}
|
|
4311
|
+
const userResponse = await get_user_response(
|
|
4312
|
+
prompt,
|
|
4313
|
+
components,
|
|
4314
|
+
anthropicApiKey,
|
|
4315
|
+
groqApiKey,
|
|
4316
|
+
llmProviders,
|
|
4317
|
+
logCollector,
|
|
4318
|
+
conversationHistory,
|
|
4319
|
+
responseMode,
|
|
4320
|
+
streamCallback,
|
|
4321
|
+
collections
|
|
4322
|
+
);
|
|
3764
4323
|
logCollector.info("User prompt request completed");
|
|
3765
4324
|
const uiBlockId = existingUiBlockId;
|
|
3766
4325
|
if (!userResponse.success) {
|
|
@@ -3783,10 +4342,11 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3783
4342
|
component = userResponse.data.component;
|
|
3784
4343
|
}
|
|
3785
4344
|
if ("textResponse" in userResponse.data) {
|
|
3786
|
-
textResponse = userResponse.data.
|
|
4345
|
+
textResponse = userResponse.data.text;
|
|
3787
4346
|
}
|
|
3788
4347
|
}
|
|
3789
4348
|
}
|
|
4349
|
+
const finalTextResponse = responseMode === "text" && accumulatedStreamResponse ? accumulatedStreamResponse : textResponse;
|
|
3790
4350
|
const uiBlock = new UIBlock(
|
|
3791
4351
|
prompt,
|
|
3792
4352
|
{},
|
|
@@ -3796,8 +4356,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3796
4356
|
[],
|
|
3797
4357
|
// actions: empty initially
|
|
3798
4358
|
uiBlockId,
|
|
3799
|
-
|
|
3800
|
-
// textResponse:
|
|
4359
|
+
finalTextResponse
|
|
4360
|
+
// textResponse: FULL streaming response including all intermediate messages
|
|
3801
4361
|
);
|
|
3802
4362
|
thread.addUIBlock(uiBlock);
|
|
3803
4363
|
logger.info(`Created UIBlock: ${uiBlockId} in Thread: ${threadId}`);
|
|
@@ -3811,8 +4371,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3811
4371
|
wsId
|
|
3812
4372
|
};
|
|
3813
4373
|
};
|
|
3814
|
-
async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders) {
|
|
3815
|
-
const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders);
|
|
4374
|
+
async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections) {
|
|
4375
|
+
const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections);
|
|
3816
4376
|
sendDataResponse4(
|
|
3817
4377
|
response.id || data.id,
|
|
3818
4378
|
{
|
|
@@ -4888,7 +5448,7 @@ function sendResponse5(id, res, sendMessage, clientId) {
|
|
|
4888
5448
|
}
|
|
4889
5449
|
|
|
4890
5450
|
// src/auth/user-manager.ts
|
|
4891
|
-
import
|
|
5451
|
+
import fs5 from "fs";
|
|
4892
5452
|
import path4 from "path";
|
|
4893
5453
|
import os from "os";
|
|
4894
5454
|
var UserManager = class {
|
|
@@ -4928,19 +5488,19 @@ var UserManager = class {
|
|
|
4928
5488
|
async loadUsersFromFile() {
|
|
4929
5489
|
try {
|
|
4930
5490
|
const dir = path4.dirname(this.filePath);
|
|
4931
|
-
if (!
|
|
5491
|
+
if (!fs5.existsSync(dir)) {
|
|
4932
5492
|
logger.info(`Creating directory structure: ${dir}`);
|
|
4933
|
-
|
|
5493
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
4934
5494
|
}
|
|
4935
|
-
if (!
|
|
5495
|
+
if (!fs5.existsSync(this.filePath)) {
|
|
4936
5496
|
logger.info(`Users file does not exist at ${this.filePath}, creating with empty users`);
|
|
4937
5497
|
const initialData = { users: [] };
|
|
4938
|
-
|
|
5498
|
+
fs5.writeFileSync(this.filePath, JSON.stringify(initialData, null, 4));
|
|
4939
5499
|
this.users = [];
|
|
4940
5500
|
this.hasChanged = false;
|
|
4941
5501
|
return;
|
|
4942
5502
|
}
|
|
4943
|
-
const fileContent =
|
|
5503
|
+
const fileContent = fs5.readFileSync(this.filePath, "utf-8");
|
|
4944
5504
|
const rawData = JSON.parse(fileContent);
|
|
4945
5505
|
const validatedData = UsersDataSchema.parse(rawData);
|
|
4946
5506
|
this.users = validatedData.users;
|
|
@@ -4960,15 +5520,15 @@ var UserManager = class {
|
|
|
4960
5520
|
}
|
|
4961
5521
|
try {
|
|
4962
5522
|
const dir = path4.dirname(this.filePath);
|
|
4963
|
-
if (!
|
|
4964
|
-
|
|
5523
|
+
if (!fs5.existsSync(dir)) {
|
|
5524
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
4965
5525
|
}
|
|
4966
5526
|
const usersToSave = this.users.map((user) => {
|
|
4967
5527
|
const { wsIds, ...userWithoutWsIds } = user;
|
|
4968
5528
|
return userWithoutWsIds;
|
|
4969
5529
|
});
|
|
4970
5530
|
const data = { users: usersToSave };
|
|
4971
|
-
|
|
5531
|
+
fs5.writeFileSync(this.filePath, JSON.stringify(data, null, 4));
|
|
4972
5532
|
this.hasChanged = false;
|
|
4973
5533
|
logger.debug(`Synced ${this.users.length} users to file (wsIds excluded)`);
|
|
4974
5534
|
} catch (error) {
|
|
@@ -5186,7 +5746,7 @@ var UserManager = class {
|
|
|
5186
5746
|
};
|
|
5187
5747
|
|
|
5188
5748
|
// src/dashboards/dashboard-manager.ts
|
|
5189
|
-
import
|
|
5749
|
+
import fs6 from "fs";
|
|
5190
5750
|
import path5 from "path";
|
|
5191
5751
|
import os2 from "os";
|
|
5192
5752
|
var DashboardManager = class {
|
|
@@ -5221,12 +5781,12 @@ var DashboardManager = class {
|
|
|
5221
5781
|
createDashboard(dashboardId, dashboard) {
|
|
5222
5782
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5223
5783
|
const dashboardDir = path5.dirname(dashboardPath);
|
|
5224
|
-
if (
|
|
5784
|
+
if (fs6.existsSync(dashboardPath)) {
|
|
5225
5785
|
throw new Error(`Dashboard '${dashboardId}' already exists`);
|
|
5226
5786
|
}
|
|
5227
5787
|
const validated = DSLRendererPropsSchema.parse(dashboard);
|
|
5228
|
-
|
|
5229
|
-
|
|
5788
|
+
fs6.mkdirSync(dashboardDir, { recursive: true });
|
|
5789
|
+
fs6.writeFileSync(dashboardPath, JSON.stringify(validated, null, 4));
|
|
5230
5790
|
logger.info(`Dashboard created: ${dashboardId}`);
|
|
5231
5791
|
return validated;
|
|
5232
5792
|
}
|
|
@@ -5237,12 +5797,12 @@ var DashboardManager = class {
|
|
|
5237
5797
|
*/
|
|
5238
5798
|
getDashboard(dashboardId) {
|
|
5239
5799
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5240
|
-
if (!
|
|
5800
|
+
if (!fs6.existsSync(dashboardPath)) {
|
|
5241
5801
|
logger.warn(`Dashboard not found: ${dashboardId}`);
|
|
5242
5802
|
return null;
|
|
5243
5803
|
}
|
|
5244
5804
|
try {
|
|
5245
|
-
const fileContent =
|
|
5805
|
+
const fileContent = fs6.readFileSync(dashboardPath, "utf-8");
|
|
5246
5806
|
const dashboard = JSON.parse(fileContent);
|
|
5247
5807
|
const validated = DSLRendererPropsSchema.parse(dashboard);
|
|
5248
5808
|
return validated;
|
|
@@ -5256,16 +5816,16 @@ var DashboardManager = class {
|
|
|
5256
5816
|
* @returns Array of dashboard objects with their IDs
|
|
5257
5817
|
*/
|
|
5258
5818
|
getAllDashboards() {
|
|
5259
|
-
if (!
|
|
5260
|
-
|
|
5819
|
+
if (!fs6.existsSync(this.dashboardsBasePath)) {
|
|
5820
|
+
fs6.mkdirSync(this.dashboardsBasePath, { recursive: true });
|
|
5261
5821
|
return [];
|
|
5262
5822
|
}
|
|
5263
5823
|
const dashboards = [];
|
|
5264
5824
|
try {
|
|
5265
|
-
const dashboardDirs =
|
|
5825
|
+
const dashboardDirs = fs6.readdirSync(this.dashboardsBasePath);
|
|
5266
5826
|
for (const dashboardId of dashboardDirs) {
|
|
5267
5827
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5268
|
-
if (
|
|
5828
|
+
if (fs6.existsSync(dashboardPath)) {
|
|
5269
5829
|
const dashboard = this.getDashboard(dashboardId);
|
|
5270
5830
|
if (dashboard) {
|
|
5271
5831
|
dashboards.push({ dashboardId, dashboard });
|
|
@@ -5287,13 +5847,13 @@ var DashboardManager = class {
|
|
|
5287
5847
|
*/
|
|
5288
5848
|
updateDashboard(dashboardId, dashboard) {
|
|
5289
5849
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5290
|
-
if (!
|
|
5850
|
+
if (!fs6.existsSync(dashboardPath)) {
|
|
5291
5851
|
logger.warn(`Dashboard not found for update: ${dashboardId}`);
|
|
5292
5852
|
return null;
|
|
5293
5853
|
}
|
|
5294
5854
|
try {
|
|
5295
5855
|
const validated = DSLRendererPropsSchema.parse(dashboard);
|
|
5296
|
-
|
|
5856
|
+
fs6.writeFileSync(dashboardPath, JSON.stringify(validated, null, 4));
|
|
5297
5857
|
logger.info(`Dashboard updated: ${dashboardId}`);
|
|
5298
5858
|
return validated;
|
|
5299
5859
|
} catch (error) {
|
|
@@ -5309,12 +5869,12 @@ var DashboardManager = class {
|
|
|
5309
5869
|
deleteDashboard(dashboardId) {
|
|
5310
5870
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5311
5871
|
const dashboardDir = path5.dirname(dashboardPath);
|
|
5312
|
-
if (!
|
|
5872
|
+
if (!fs6.existsSync(dashboardPath)) {
|
|
5313
5873
|
logger.warn(`Dashboard not found for deletion: ${dashboardId}`);
|
|
5314
5874
|
return false;
|
|
5315
5875
|
}
|
|
5316
5876
|
try {
|
|
5317
|
-
|
|
5877
|
+
fs6.rmSync(dashboardDir, { recursive: true, force: true });
|
|
5318
5878
|
logger.info(`Dashboard deleted: ${dashboardId}`);
|
|
5319
5879
|
return true;
|
|
5320
5880
|
} catch (error) {
|
|
@@ -5329,21 +5889,21 @@ var DashboardManager = class {
|
|
|
5329
5889
|
*/
|
|
5330
5890
|
dashboardExists(dashboardId) {
|
|
5331
5891
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5332
|
-
return
|
|
5892
|
+
return fs6.existsSync(dashboardPath);
|
|
5333
5893
|
}
|
|
5334
5894
|
/**
|
|
5335
5895
|
* Get dashboard count
|
|
5336
5896
|
* @returns Number of dashboards
|
|
5337
5897
|
*/
|
|
5338
5898
|
getDashboardCount() {
|
|
5339
|
-
if (!
|
|
5899
|
+
if (!fs6.existsSync(this.dashboardsBasePath)) {
|
|
5340
5900
|
return 0;
|
|
5341
5901
|
}
|
|
5342
5902
|
try {
|
|
5343
|
-
const dashboardDirs =
|
|
5903
|
+
const dashboardDirs = fs6.readdirSync(this.dashboardsBasePath);
|
|
5344
5904
|
return dashboardDirs.filter((dir) => {
|
|
5345
5905
|
const dashboardPath = this.getDashboardPath(dir);
|
|
5346
|
-
return
|
|
5906
|
+
return fs6.existsSync(dashboardPath);
|
|
5347
5907
|
}).length;
|
|
5348
5908
|
} catch (error) {
|
|
5349
5909
|
logger.error("Failed to get dashboard count:", error);
|
|
@@ -5353,7 +5913,7 @@ var DashboardManager = class {
|
|
|
5353
5913
|
};
|
|
5354
5914
|
|
|
5355
5915
|
// src/reports/report-manager.ts
|
|
5356
|
-
import
|
|
5916
|
+
import fs7 from "fs";
|
|
5357
5917
|
import path6 from "path";
|
|
5358
5918
|
import os3 from "os";
|
|
5359
5919
|
var ReportManager = class {
|
|
@@ -5388,12 +5948,12 @@ var ReportManager = class {
|
|
|
5388
5948
|
createReport(reportId, report) {
|
|
5389
5949
|
const reportPath = this.getReportPath(reportId);
|
|
5390
5950
|
const reportDir = path6.dirname(reportPath);
|
|
5391
|
-
if (
|
|
5951
|
+
if (fs7.existsSync(reportPath)) {
|
|
5392
5952
|
throw new Error(`Report '${reportId}' already exists`);
|
|
5393
5953
|
}
|
|
5394
5954
|
const validated = DSLRendererPropsSchema2.parse(report);
|
|
5395
|
-
|
|
5396
|
-
|
|
5955
|
+
fs7.mkdirSync(reportDir, { recursive: true });
|
|
5956
|
+
fs7.writeFileSync(reportPath, JSON.stringify(validated, null, 4));
|
|
5397
5957
|
logger.info(`Report created: ${reportId}`);
|
|
5398
5958
|
return validated;
|
|
5399
5959
|
}
|
|
@@ -5404,12 +5964,12 @@ var ReportManager = class {
|
|
|
5404
5964
|
*/
|
|
5405
5965
|
getReport(reportId) {
|
|
5406
5966
|
const reportPath = this.getReportPath(reportId);
|
|
5407
|
-
if (!
|
|
5967
|
+
if (!fs7.existsSync(reportPath)) {
|
|
5408
5968
|
logger.warn(`Report not found: ${reportId}`);
|
|
5409
5969
|
return null;
|
|
5410
5970
|
}
|
|
5411
5971
|
try {
|
|
5412
|
-
const fileContent =
|
|
5972
|
+
const fileContent = fs7.readFileSync(reportPath, "utf-8");
|
|
5413
5973
|
const report = JSON.parse(fileContent);
|
|
5414
5974
|
const validated = DSLRendererPropsSchema2.parse(report);
|
|
5415
5975
|
return validated;
|
|
@@ -5423,16 +5983,16 @@ var ReportManager = class {
|
|
|
5423
5983
|
* @returns Array of report objects with their IDs
|
|
5424
5984
|
*/
|
|
5425
5985
|
getAllReports() {
|
|
5426
|
-
if (!
|
|
5427
|
-
|
|
5986
|
+
if (!fs7.existsSync(this.reportsBasePath)) {
|
|
5987
|
+
fs7.mkdirSync(this.reportsBasePath, { recursive: true });
|
|
5428
5988
|
return [];
|
|
5429
5989
|
}
|
|
5430
5990
|
const reports = [];
|
|
5431
5991
|
try {
|
|
5432
|
-
const reportDirs =
|
|
5992
|
+
const reportDirs = fs7.readdirSync(this.reportsBasePath);
|
|
5433
5993
|
for (const reportId of reportDirs) {
|
|
5434
5994
|
const reportPath = this.getReportPath(reportId);
|
|
5435
|
-
if (
|
|
5995
|
+
if (fs7.existsSync(reportPath)) {
|
|
5436
5996
|
const report = this.getReport(reportId);
|
|
5437
5997
|
if (report) {
|
|
5438
5998
|
reports.push({ reportId, report });
|
|
@@ -5454,13 +6014,13 @@ var ReportManager = class {
|
|
|
5454
6014
|
*/
|
|
5455
6015
|
updateReport(reportId, report) {
|
|
5456
6016
|
const reportPath = this.getReportPath(reportId);
|
|
5457
|
-
if (!
|
|
6017
|
+
if (!fs7.existsSync(reportPath)) {
|
|
5458
6018
|
logger.warn(`Report not found for update: ${reportId}`);
|
|
5459
6019
|
return null;
|
|
5460
6020
|
}
|
|
5461
6021
|
try {
|
|
5462
6022
|
const validated = DSLRendererPropsSchema2.parse(report);
|
|
5463
|
-
|
|
6023
|
+
fs7.writeFileSync(reportPath, JSON.stringify(validated, null, 4));
|
|
5464
6024
|
logger.info(`Report updated: ${reportId}`);
|
|
5465
6025
|
return validated;
|
|
5466
6026
|
} catch (error) {
|
|
@@ -5476,12 +6036,12 @@ var ReportManager = class {
|
|
|
5476
6036
|
deleteReport(reportId) {
|
|
5477
6037
|
const reportPath = this.getReportPath(reportId);
|
|
5478
6038
|
const reportDir = path6.dirname(reportPath);
|
|
5479
|
-
if (!
|
|
6039
|
+
if (!fs7.existsSync(reportPath)) {
|
|
5480
6040
|
logger.warn(`Report not found for deletion: ${reportId}`);
|
|
5481
6041
|
return false;
|
|
5482
6042
|
}
|
|
5483
6043
|
try {
|
|
5484
|
-
|
|
6044
|
+
fs7.rmSync(reportDir, { recursive: true, force: true });
|
|
5485
6045
|
logger.info(`Report deleted: ${reportId}`);
|
|
5486
6046
|
return true;
|
|
5487
6047
|
} catch (error) {
|
|
@@ -5496,21 +6056,21 @@ var ReportManager = class {
|
|
|
5496
6056
|
*/
|
|
5497
6057
|
reportExists(reportId) {
|
|
5498
6058
|
const reportPath = this.getReportPath(reportId);
|
|
5499
|
-
return
|
|
6059
|
+
return fs7.existsSync(reportPath);
|
|
5500
6060
|
}
|
|
5501
6061
|
/**
|
|
5502
6062
|
* Get report count
|
|
5503
6063
|
* @returns Number of reports
|
|
5504
6064
|
*/
|
|
5505
6065
|
getReportCount() {
|
|
5506
|
-
if (!
|
|
6066
|
+
if (!fs7.existsSync(this.reportsBasePath)) {
|
|
5507
6067
|
return 0;
|
|
5508
6068
|
}
|
|
5509
6069
|
try {
|
|
5510
|
-
const reportDirs =
|
|
6070
|
+
const reportDirs = fs7.readdirSync(this.reportsBasePath);
|
|
5511
6071
|
return reportDirs.filter((dir) => {
|
|
5512
6072
|
const reportPath = this.getReportPath(dir);
|
|
5513
|
-
return
|
|
6073
|
+
return fs7.existsSync(reportPath);
|
|
5514
6074
|
}).length;
|
|
5515
6075
|
} catch (error) {
|
|
5516
6076
|
logger.error("Failed to get report count:", error);
|
|
@@ -5734,9 +6294,6 @@ var SuperatomSDK = class {
|
|
|
5734
6294
|
});
|
|
5735
6295
|
this.initializeDashboardManager();
|
|
5736
6296
|
this.initializeReportManager();
|
|
5737
|
-
this.connect().catch((error) => {
|
|
5738
|
-
logger.error("Failed to connect to Superatom:", error);
|
|
5739
|
-
});
|
|
5740
6297
|
}
|
|
5741
6298
|
/**
|
|
5742
6299
|
* Initialize PromptLoader and load prompts into memory
|
|
@@ -5802,6 +6359,10 @@ var SuperatomSDK = class {
|
|
|
5802
6359
|
* Connect to the Superatom WebSocket service
|
|
5803
6360
|
*/
|
|
5804
6361
|
async connect() {
|
|
6362
|
+
if (this.connected && this.ws && this.ws.readyState === this.ws.OPEN) {
|
|
6363
|
+
logger.info("Already connected to WebSocket");
|
|
6364
|
+
return Promise.resolve();
|
|
6365
|
+
}
|
|
5805
6366
|
return new Promise((resolve, reject) => {
|
|
5806
6367
|
try {
|
|
5807
6368
|
const url = new URL(this.url);
|
|
@@ -5864,7 +6425,7 @@ var SuperatomSDK = class {
|
|
|
5864
6425
|
});
|
|
5865
6426
|
break;
|
|
5866
6427
|
case "USER_PROMPT_REQ":
|
|
5867
|
-
handleUserPromptRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.llmProviders).catch((error) => {
|
|
6428
|
+
handleUserPromptRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.llmProviders, this.collections).catch((error) => {
|
|
5868
6429
|
logger.error("Failed to handle user prompt request:", error);
|
|
5869
6430
|
});
|
|
5870
6431
|
break;
|