@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.js
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __commonJS = (cb, mod) => function __require() {
|
|
9
12
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
13
|
};
|
|
@@ -102,7 +105,7 @@ var require_package = __commonJS({
|
|
|
102
105
|
var require_main = __commonJS({
|
|
103
106
|
"node_modules/dotenv/lib/main.js"(exports2, module2) {
|
|
104
107
|
"use strict";
|
|
105
|
-
var
|
|
108
|
+
var fs8 = require("fs");
|
|
106
109
|
var path7 = require("path");
|
|
107
110
|
var os4 = require("os");
|
|
108
111
|
var crypto2 = require("crypto");
|
|
@@ -244,7 +247,7 @@ var require_main = __commonJS({
|
|
|
244
247
|
if (options && options.path && options.path.length > 0) {
|
|
245
248
|
if (Array.isArray(options.path)) {
|
|
246
249
|
for (const filepath of options.path) {
|
|
247
|
-
if (
|
|
250
|
+
if (fs8.existsSync(filepath)) {
|
|
248
251
|
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
249
252
|
}
|
|
250
253
|
}
|
|
@@ -254,7 +257,7 @@ var require_main = __commonJS({
|
|
|
254
257
|
} else {
|
|
255
258
|
possibleVaultPath = path7.resolve(process.cwd(), ".env.vault");
|
|
256
259
|
}
|
|
257
|
-
if (
|
|
260
|
+
if (fs8.existsSync(possibleVaultPath)) {
|
|
258
261
|
return possibleVaultPath;
|
|
259
262
|
}
|
|
260
263
|
return null;
|
|
@@ -307,7 +310,7 @@ var require_main = __commonJS({
|
|
|
307
310
|
const parsedAll = {};
|
|
308
311
|
for (const path8 of optionPaths) {
|
|
309
312
|
try {
|
|
310
|
-
const parsed = DotenvModule.parse(
|
|
313
|
+
const parsed = DotenvModule.parse(fs8.readFileSync(path8, { encoding }));
|
|
311
314
|
DotenvModule.populate(parsedAll, parsed, options);
|
|
312
315
|
} catch (e) {
|
|
313
316
|
if (debug) {
|
|
@@ -428,6 +431,128 @@ var require_main = __commonJS({
|
|
|
428
431
|
}
|
|
429
432
|
});
|
|
430
433
|
|
|
434
|
+
// src/userResponse/utils.ts
|
|
435
|
+
var utils_exports = {};
|
|
436
|
+
__export(utils_exports, {
|
|
437
|
+
convertTopToLimit: () => convertTopToLimit,
|
|
438
|
+
ensureQueryLimit: () => ensureQueryLimit,
|
|
439
|
+
fixScalarSubqueries: () => fixScalarSubqueries,
|
|
440
|
+
getJsonSizeInBytes: () => getJsonSizeInBytes,
|
|
441
|
+
validateMessageSize: () => validateMessageSize
|
|
442
|
+
});
|
|
443
|
+
function convertTopToLimit(query) {
|
|
444
|
+
if (!query || query.trim().length === 0) {
|
|
445
|
+
return query;
|
|
446
|
+
}
|
|
447
|
+
let modifiedQuery = query.replace(/\bSELECT\s+TOP\s+(\d+)\b/gi, "SELECT");
|
|
448
|
+
if (modifiedQuery !== query) {
|
|
449
|
+
console.warn(`\u26A0\uFE0F Query had TOP syntax. Converting to LIMIT for Snowflake compatibility.`);
|
|
450
|
+
}
|
|
451
|
+
return modifiedQuery;
|
|
452
|
+
}
|
|
453
|
+
function ensureQueryLimit(query, defaultLimit = 32, maxLimit = 32) {
|
|
454
|
+
if (!query || query.trim().length === 0) {
|
|
455
|
+
return query;
|
|
456
|
+
}
|
|
457
|
+
let trimmedQuery = query.trim();
|
|
458
|
+
const isSelectQuery = /^\s*SELECT\b/i.test(trimmedQuery) || /^\s*WITH\b.*\bSELECT\b/is.test(trimmedQuery);
|
|
459
|
+
if (!isSelectQuery) {
|
|
460
|
+
return query;
|
|
461
|
+
}
|
|
462
|
+
trimmedQuery = convertTopToLimit(trimmedQuery);
|
|
463
|
+
const hadSemicolon = trimmedQuery.endsWith(";");
|
|
464
|
+
if (hadSemicolon) {
|
|
465
|
+
trimmedQuery = trimmedQuery.slice(0, -1).trim();
|
|
466
|
+
}
|
|
467
|
+
const limitMatches = trimmedQuery.match(/\bLIMIT\s+(\d+)\b/gi);
|
|
468
|
+
if (limitMatches && limitMatches.length > 0) {
|
|
469
|
+
if (limitMatches.length > 1) {
|
|
470
|
+
console.warn(`\u26A0\uFE0F Query had ${limitMatches.length} LIMIT clauses. Removing duplicates...`);
|
|
471
|
+
trimmedQuery = trimmedQuery.replace(/\s*\bLIMIT\s+\d+\b/gi, "").trim();
|
|
472
|
+
} else {
|
|
473
|
+
const existingLimitMatch = trimmedQuery.match(/\bLIMIT\s+(\d+)\b/i);
|
|
474
|
+
if (existingLimitMatch) {
|
|
475
|
+
const existingLimit = parseInt(existingLimitMatch[1], 10);
|
|
476
|
+
if (existingLimit <= maxLimit) {
|
|
477
|
+
if (hadSemicolon) {
|
|
478
|
+
trimmedQuery += ";";
|
|
479
|
+
}
|
|
480
|
+
return trimmedQuery;
|
|
481
|
+
}
|
|
482
|
+
console.warn(`\u26A0\uFE0F Query LIMIT ${existingLimit} exceeds maximum of ${maxLimit}. Reducing to ${maxLimit}...`);
|
|
483
|
+
trimmedQuery = trimmedQuery.replace(/\bLIMIT\s+\d+\b/i, `LIMIT ${maxLimit}`);
|
|
484
|
+
if (hadSemicolon) {
|
|
485
|
+
trimmedQuery += ";";
|
|
486
|
+
}
|
|
487
|
+
return trimmedQuery;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
trimmedQuery = `${trimmedQuery} LIMIT ${defaultLimit}`;
|
|
492
|
+
if (hadSemicolon) {
|
|
493
|
+
trimmedQuery += ";";
|
|
494
|
+
}
|
|
495
|
+
return trimmedQuery;
|
|
496
|
+
}
|
|
497
|
+
function fixScalarSubqueries(query) {
|
|
498
|
+
if (!query || query.trim().length === 0) {
|
|
499
|
+
return query;
|
|
500
|
+
}
|
|
501
|
+
let modifiedQuery = query;
|
|
502
|
+
let hasChanges = false;
|
|
503
|
+
const scalarOperatorPattern = /([=<>!]=?|<>)\s*\(\s*SELECT\s/gi;
|
|
504
|
+
const matches = [...modifiedQuery.matchAll(scalarOperatorPattern)];
|
|
505
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
506
|
+
const match = matches[i];
|
|
507
|
+
const startPos = match.index + match[0].length - "SELECT ".length;
|
|
508
|
+
let parenDepth = 1;
|
|
509
|
+
let endPos = startPos;
|
|
510
|
+
let foundEnd = false;
|
|
511
|
+
for (let j = startPos; j < modifiedQuery.length; j++) {
|
|
512
|
+
const char = modifiedQuery[j];
|
|
513
|
+
if (char === "(") parenDepth++;
|
|
514
|
+
if (char === ")") {
|
|
515
|
+
parenDepth--;
|
|
516
|
+
if (parenDepth === 0) {
|
|
517
|
+
endPos = j;
|
|
518
|
+
foundEnd = true;
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (!foundEnd) continue;
|
|
524
|
+
const subquery = modifiedQuery.substring(startPos, endPos);
|
|
525
|
+
if (/\bLIMIT\s+\d+/i.test(subquery)) {
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
const fixedSubquery = subquery.trim() + " LIMIT 1";
|
|
529
|
+
modifiedQuery = modifiedQuery.substring(0, startPos) + fixedSubquery + modifiedQuery.substring(endPos);
|
|
530
|
+
hasChanges = true;
|
|
531
|
+
console.warn(`\u26A0\uFE0F Fixed scalar subquery: added LIMIT 1 to prevent multiple row error`);
|
|
532
|
+
}
|
|
533
|
+
if (hasChanges) {
|
|
534
|
+
console.log("\u2713 Query validated and fixed for PostgreSQL scalar subquery compatibility");
|
|
535
|
+
}
|
|
536
|
+
return modifiedQuery;
|
|
537
|
+
}
|
|
538
|
+
function getJsonSizeInBytes(obj) {
|
|
539
|
+
const jsonString = JSON.stringify(obj);
|
|
540
|
+
return Buffer.byteLength(jsonString, "utf8");
|
|
541
|
+
}
|
|
542
|
+
function validateMessageSize(message, maxSize = 1048576) {
|
|
543
|
+
const size = getJsonSizeInBytes(message);
|
|
544
|
+
return {
|
|
545
|
+
isValid: size <= maxSize,
|
|
546
|
+
size,
|
|
547
|
+
maxSize
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
var init_utils = __esm({
|
|
551
|
+
"src/userResponse/utils.ts"() {
|
|
552
|
+
"use strict";
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
|
|
431
556
|
// src/index.ts
|
|
432
557
|
var index_exports = {};
|
|
433
558
|
__export(index_exports, {
|
|
@@ -707,7 +832,8 @@ var UserPromptRequestPayloadSchema = import_zod3.z.object({
|
|
|
707
832
|
SA_RUNTIME: import_zod3.z.object({
|
|
708
833
|
threadId: import_zod3.z.string(),
|
|
709
834
|
uiBlockId: import_zod3.z.string()
|
|
710
|
-
}).optional()
|
|
835
|
+
}).optional(),
|
|
836
|
+
responseMode: import_zod3.z.enum(["component", "text"]).optional()
|
|
711
837
|
});
|
|
712
838
|
var UserPromptRequestMessageSchema = import_zod3.z.object({
|
|
713
839
|
id: import_zod3.z.string(),
|
|
@@ -822,7 +948,9 @@ var ReportsRequestMessageSchema = import_zod3.z.object({
|
|
|
822
948
|
});
|
|
823
949
|
|
|
824
950
|
// src/utils/logger.ts
|
|
951
|
+
var import_fs = __toESM(require("fs"));
|
|
825
952
|
var PREFIX = "[SuperatomSDK]";
|
|
953
|
+
var LOGSTREAM = import_fs.default.createWriteStream("superatom-sdk.log", { flags: "a" });
|
|
826
954
|
var LOG_LEVEL_PRIORITY = {
|
|
827
955
|
errors: 0,
|
|
828
956
|
warnings: 1,
|
|
@@ -906,6 +1034,9 @@ var Logger = class {
|
|
|
906
1034
|
console.log(PREFIX, "[DEBUG]", ...args);
|
|
907
1035
|
}
|
|
908
1036
|
}
|
|
1037
|
+
file(...args) {
|
|
1038
|
+
LOGSTREAM.write(args.join(" ") + "\n");
|
|
1039
|
+
}
|
|
909
1040
|
};
|
|
910
1041
|
var logger = new Logger();
|
|
911
1042
|
|
|
@@ -977,6 +1108,9 @@ var UIBlock = class {
|
|
|
977
1108
|
getComponentMetadata() {
|
|
978
1109
|
return this.generatedComponentMetadata;
|
|
979
1110
|
}
|
|
1111
|
+
getTextResponse() {
|
|
1112
|
+
return this.textResponse || "";
|
|
1113
|
+
}
|
|
980
1114
|
/**
|
|
981
1115
|
* Set or update component metadata
|
|
982
1116
|
*/
|
|
@@ -1069,12 +1203,6 @@ var UIBlock = class {
|
|
|
1069
1203
|
const processedData = this.processDataForStorage(data);
|
|
1070
1204
|
this.componentData = { ...this.componentData, ...processedData };
|
|
1071
1205
|
}
|
|
1072
|
-
/**
|
|
1073
|
-
* Get text response
|
|
1074
|
-
*/
|
|
1075
|
-
getTextResponse() {
|
|
1076
|
-
return this.textResponse;
|
|
1077
|
-
}
|
|
1078
1206
|
/**
|
|
1079
1207
|
* Set or update text response
|
|
1080
1208
|
*/
|
|
@@ -1265,8 +1393,11 @@ var Thread = class {
|
|
|
1265
1393
|
const questionNum = index + 1;
|
|
1266
1394
|
const question = block.getUserQuestion();
|
|
1267
1395
|
const metadata = block.getComponentMetadata();
|
|
1268
|
-
|
|
1269
|
-
|
|
1396
|
+
const textResponse = block.getTextResponse();
|
|
1397
|
+
let assistantResponse = "";
|
|
1398
|
+
const hasComponent = metadata && Object.keys(metadata).length > 0 && metadata.type;
|
|
1399
|
+
const hasTextResponse = textResponse && textResponse.trim().length > 0;
|
|
1400
|
+
if (hasComponent) {
|
|
1270
1401
|
const parts = [];
|
|
1271
1402
|
if (metadata.type) {
|
|
1272
1403
|
parts.push(`Component Type: ${metadata.type}`);
|
|
@@ -1286,11 +1417,17 @@ var Thread = class {
|
|
|
1286
1417
|
const componentTypes = metadata.props.config.components.map((c) => c.type).join(", ");
|
|
1287
1418
|
parts.push(`Multi-component with: ${componentTypes}`);
|
|
1288
1419
|
}
|
|
1289
|
-
|
|
1420
|
+
assistantResponse = parts.join(", ");
|
|
1421
|
+
} else if (hasTextResponse) {
|
|
1422
|
+
assistantResponse = textResponse;
|
|
1423
|
+
} else {
|
|
1424
|
+
assistantResponse = "No response generated";
|
|
1290
1425
|
}
|
|
1291
|
-
contextLines.push(`
|
|
1292
|
-
|
|
1293
|
-
contextLines.push(
|
|
1426
|
+
contextLines.push(`User:
|
|
1427
|
+
${question}`);
|
|
1428
|
+
contextLines.push(`Assistant:
|
|
1429
|
+
${assistantResponse}`);
|
|
1430
|
+
contextLines.push("---");
|
|
1294
1431
|
});
|
|
1295
1432
|
return contextLines.join("\n").trim();
|
|
1296
1433
|
}
|
|
@@ -1466,7 +1603,7 @@ function sendDataResponse(id, collection, op, data, meta, sendMessage) {
|
|
|
1466
1603
|
}
|
|
1467
1604
|
|
|
1468
1605
|
// src/bundle.ts
|
|
1469
|
-
var
|
|
1606
|
+
var fs2 = __toESM(require("fs"));
|
|
1470
1607
|
var path = __toESM(require("path"));
|
|
1471
1608
|
function getBundleDir(configDir) {
|
|
1472
1609
|
const bundleDir = configDir || process.env.SA_BUNDLE_DIR;
|
|
@@ -1479,16 +1616,16 @@ function getBundleDir(configDir) {
|
|
|
1479
1616
|
}
|
|
1480
1617
|
function getJS(bundleDir) {
|
|
1481
1618
|
try {
|
|
1482
|
-
if (!
|
|
1619
|
+
if (!fs2.existsSync(bundleDir)) {
|
|
1483
1620
|
throw new Error(`Bundle directory does not exist: ${bundleDir}`);
|
|
1484
1621
|
}
|
|
1485
|
-
const stats =
|
|
1622
|
+
const stats = fs2.statSync(bundleDir);
|
|
1486
1623
|
if (!stats.isDirectory()) {
|
|
1487
1624
|
throw new Error(`Bundle path is not a directory: ${bundleDir}`);
|
|
1488
1625
|
}
|
|
1489
1626
|
let files;
|
|
1490
1627
|
try {
|
|
1491
|
-
files =
|
|
1628
|
+
files = fs2.readdirSync(bundleDir);
|
|
1492
1629
|
} catch (error) {
|
|
1493
1630
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1494
1631
|
throw new Error(`Failed to read bundle directory: ${errorMessage}`);
|
|
@@ -1503,7 +1640,7 @@ function getJS(bundleDir) {
|
|
|
1503
1640
|
const filePath = path.join(bundleDir, indexFile);
|
|
1504
1641
|
logger.info(`Loading bundle from ${filePath}`);
|
|
1505
1642
|
try {
|
|
1506
|
-
return
|
|
1643
|
+
return fs2.readFileSync(filePath, "utf8");
|
|
1507
1644
|
} catch (error) {
|
|
1508
1645
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1509
1646
|
throw new Error(`Failed to read bundle file: ${errorMessage}`);
|
|
@@ -1909,94 +2046,12 @@ function sendDataResponse3(id, res, sendMessage, clientId) {
|
|
|
1909
2046
|
// src/userResponse/groq.ts
|
|
1910
2047
|
var import_dotenv = __toESM(require_main());
|
|
1911
2048
|
|
|
1912
|
-
// src/userResponse/
|
|
1913
|
-
|
|
1914
|
-
if (!query || query.trim().length === 0) {
|
|
1915
|
-
return query;
|
|
1916
|
-
}
|
|
1917
|
-
let modifiedQuery = query.replace(/\bSELECT\s+TOP\s+(\d+)\b/gi, "SELECT");
|
|
1918
|
-
if (modifiedQuery !== query) {
|
|
1919
|
-
console.warn(`\u26A0\uFE0F Query had TOP syntax. Converting to LIMIT for Snowflake compatibility.`);
|
|
1920
|
-
}
|
|
1921
|
-
return modifiedQuery;
|
|
1922
|
-
}
|
|
1923
|
-
function ensureQueryLimit(query, defaultLimit = 50) {
|
|
1924
|
-
if (!query || query.trim().length === 0) {
|
|
1925
|
-
return query;
|
|
1926
|
-
}
|
|
1927
|
-
let trimmedQuery = query.trim();
|
|
1928
|
-
const isSelectQuery = /^\s*SELECT\b/i.test(trimmedQuery) || /^\s*WITH\b.*\bSELECT\b/is.test(trimmedQuery);
|
|
1929
|
-
if (!isSelectQuery) {
|
|
1930
|
-
return query;
|
|
1931
|
-
}
|
|
1932
|
-
trimmedQuery = convertTopToLimit(trimmedQuery);
|
|
1933
|
-
const hadSemicolon = trimmedQuery.endsWith(";");
|
|
1934
|
-
if (hadSemicolon) {
|
|
1935
|
-
trimmedQuery = trimmedQuery.slice(0, -1).trim();
|
|
1936
|
-
}
|
|
1937
|
-
const limitMatches = trimmedQuery.match(/\bLIMIT\s+\d+\b/gi);
|
|
1938
|
-
if (limitMatches && limitMatches.length > 0) {
|
|
1939
|
-
if (limitMatches.length > 1) {
|
|
1940
|
-
console.warn(`\u26A0\uFE0F Query had ${limitMatches.length} LIMIT clauses. Removing duplicates...`);
|
|
1941
|
-
trimmedQuery = trimmedQuery.replace(/\s*\bLIMIT\s+\d+\b/gi, "").trim();
|
|
1942
|
-
} else {
|
|
1943
|
-
if (hadSemicolon) {
|
|
1944
|
-
trimmedQuery += ";";
|
|
1945
|
-
}
|
|
1946
|
-
return trimmedQuery;
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
1949
|
-
trimmedQuery = `${trimmedQuery} LIMIT ${defaultLimit}`;
|
|
1950
|
-
if (hadSemicolon) {
|
|
1951
|
-
trimmedQuery += ";";
|
|
1952
|
-
}
|
|
1953
|
-
return trimmedQuery;
|
|
1954
|
-
}
|
|
1955
|
-
function fixScalarSubqueries(query) {
|
|
1956
|
-
if (!query || query.trim().length === 0) {
|
|
1957
|
-
return query;
|
|
1958
|
-
}
|
|
1959
|
-
let modifiedQuery = query;
|
|
1960
|
-
let hasChanges = false;
|
|
1961
|
-
const scalarOperatorPattern = /([=<>!]=?|<>)\s*\(\s*SELECT\s/gi;
|
|
1962
|
-
const matches = [...modifiedQuery.matchAll(scalarOperatorPattern)];
|
|
1963
|
-
for (let i = matches.length - 1; i >= 0; i--) {
|
|
1964
|
-
const match = matches[i];
|
|
1965
|
-
const startPos = match.index + match[0].length - "SELECT ".length;
|
|
1966
|
-
let parenDepth = 1;
|
|
1967
|
-
let endPos = startPos;
|
|
1968
|
-
let foundEnd = false;
|
|
1969
|
-
for (let j = startPos; j < modifiedQuery.length; j++) {
|
|
1970
|
-
const char = modifiedQuery[j];
|
|
1971
|
-
if (char === "(") parenDepth++;
|
|
1972
|
-
if (char === ")") {
|
|
1973
|
-
parenDepth--;
|
|
1974
|
-
if (parenDepth === 0) {
|
|
1975
|
-
endPos = j;
|
|
1976
|
-
foundEnd = true;
|
|
1977
|
-
break;
|
|
1978
|
-
}
|
|
1979
|
-
}
|
|
1980
|
-
}
|
|
1981
|
-
if (!foundEnd) continue;
|
|
1982
|
-
const subquery = modifiedQuery.substring(startPos, endPos);
|
|
1983
|
-
if (/\bLIMIT\s+\d+/i.test(subquery)) {
|
|
1984
|
-
continue;
|
|
1985
|
-
}
|
|
1986
|
-
const fixedSubquery = subquery.trim() + " LIMIT 1";
|
|
1987
|
-
modifiedQuery = modifiedQuery.substring(0, startPos) + fixedSubquery + modifiedQuery.substring(endPos);
|
|
1988
|
-
hasChanges = true;
|
|
1989
|
-
console.warn(`\u26A0\uFE0F Fixed scalar subquery: added LIMIT 1 to prevent multiple row error`);
|
|
1990
|
-
}
|
|
1991
|
-
if (hasChanges) {
|
|
1992
|
-
console.log("\u2713 Query validated and fixed for PostgreSQL scalar subquery compatibility");
|
|
1993
|
-
}
|
|
1994
|
-
return modifiedQuery;
|
|
1995
|
-
}
|
|
2049
|
+
// src/userResponse/base-llm.ts
|
|
2050
|
+
init_utils();
|
|
1996
2051
|
|
|
1997
2052
|
// src/userResponse/schema.ts
|
|
1998
2053
|
var import_path = __toESM(require("path"));
|
|
1999
|
-
var
|
|
2054
|
+
var import_fs2 = __toESM(require("fs"));
|
|
2000
2055
|
var Schema = class {
|
|
2001
2056
|
constructor(schemaFilePath) {
|
|
2002
2057
|
this.cachedSchema = null;
|
|
@@ -2010,11 +2065,11 @@ var Schema = class {
|
|
|
2010
2065
|
logger.info(`SCHEMA_FILE_PATH: ${this.schemaFilePath}`);
|
|
2011
2066
|
try {
|
|
2012
2067
|
const dir = import_path.default.dirname(this.schemaFilePath);
|
|
2013
|
-
if (!
|
|
2068
|
+
if (!import_fs2.default.existsSync(dir)) {
|
|
2014
2069
|
logger.info(`Creating directory structure: ${dir}`);
|
|
2015
|
-
|
|
2070
|
+
import_fs2.default.mkdirSync(dir, { recursive: true });
|
|
2016
2071
|
}
|
|
2017
|
-
if (!
|
|
2072
|
+
if (!import_fs2.default.existsSync(this.schemaFilePath)) {
|
|
2018
2073
|
logger.info(`Schema file does not exist at ${this.schemaFilePath}, creating with empty schema`);
|
|
2019
2074
|
const initialSchema = {
|
|
2020
2075
|
database: "",
|
|
@@ -2023,11 +2078,11 @@ var Schema = class {
|
|
|
2023
2078
|
tables: [],
|
|
2024
2079
|
relationships: []
|
|
2025
2080
|
};
|
|
2026
|
-
|
|
2081
|
+
import_fs2.default.writeFileSync(this.schemaFilePath, JSON.stringify(initialSchema, null, 4));
|
|
2027
2082
|
this.cachedSchema = initialSchema;
|
|
2028
2083
|
return initialSchema;
|
|
2029
2084
|
}
|
|
2030
|
-
const fileContent =
|
|
2085
|
+
const fileContent = import_fs2.default.readFileSync(this.schemaFilePath, "utf-8");
|
|
2031
2086
|
const schema2 = JSON.parse(fileContent);
|
|
2032
2087
|
this.cachedSchema = schema2;
|
|
2033
2088
|
return schema2;
|
|
@@ -2128,7 +2183,7 @@ var Schema = class {
|
|
|
2128
2183
|
var schema = new Schema();
|
|
2129
2184
|
|
|
2130
2185
|
// src/userResponse/prompt-loader.ts
|
|
2131
|
-
var
|
|
2186
|
+
var import_fs3 = __toESM(require("fs"));
|
|
2132
2187
|
var import_path2 = __toESM(require("path"));
|
|
2133
2188
|
var PromptLoader = class {
|
|
2134
2189
|
constructor(config) {
|
|
@@ -2156,7 +2211,8 @@ var PromptLoader = class {
|
|
|
2156
2211
|
"mutli-component",
|
|
2157
2212
|
"actions",
|
|
2158
2213
|
"container-metadata",
|
|
2159
|
-
"text-response"
|
|
2214
|
+
"text-response",
|
|
2215
|
+
"match-text-components"
|
|
2160
2216
|
];
|
|
2161
2217
|
for (const promptType of promptTypes) {
|
|
2162
2218
|
try {
|
|
@@ -2181,9 +2237,9 @@ var PromptLoader = class {
|
|
|
2181
2237
|
try {
|
|
2182
2238
|
const systemPath = import_path2.default.join(dir, promptName, "system.md");
|
|
2183
2239
|
const userPath = import_path2.default.join(dir, promptName, "user.md");
|
|
2184
|
-
if (
|
|
2185
|
-
const system =
|
|
2186
|
-
const user =
|
|
2240
|
+
if (import_fs3.default.existsSync(systemPath) && import_fs3.default.existsSync(userPath)) {
|
|
2241
|
+
const system = import_fs3.default.readFileSync(systemPath, "utf-8");
|
|
2242
|
+
const user = import_fs3.default.readFileSync(userPath, "utf-8");
|
|
2187
2243
|
logger.debug(`Loaded prompt '${promptName}' from ${dir}`);
|
|
2188
2244
|
return { system, user };
|
|
2189
2245
|
}
|
|
@@ -2305,6 +2361,14 @@ var LLM = class {
|
|
|
2305
2361
|
throw new Error(`Unsupported provider: ${provider}. Use "anthropic" or "groq"`);
|
|
2306
2362
|
}
|
|
2307
2363
|
}
|
|
2364
|
+
/* Stream response with tool calling support (Anthropic only for now) */
|
|
2365
|
+
static async streamWithTools(messages, tools, toolHandler, options = {}, maxIterations = 3) {
|
|
2366
|
+
const [provider, modelName] = this._parseModel(options.model);
|
|
2367
|
+
if (provider !== "anthropic") {
|
|
2368
|
+
throw new Error(`Tool calling is only supported for Anthropic models`);
|
|
2369
|
+
}
|
|
2370
|
+
return this._anthropicStreamWithTools(messages, tools, toolHandler, modelName, options, maxIterations);
|
|
2371
|
+
}
|
|
2308
2372
|
// ============================================================
|
|
2309
2373
|
// PRIVATE HELPER METHODS
|
|
2310
2374
|
// ============================================================
|
|
@@ -2382,6 +2446,86 @@ var LLM = class {
|
|
|
2382
2446
|
}
|
|
2383
2447
|
return fullText;
|
|
2384
2448
|
}
|
|
2449
|
+
static async _anthropicStreamWithTools(messages, tools, toolHandler, modelName, options, maxIterations) {
|
|
2450
|
+
const apiKey = options.apiKey || process.env.ANTHROPIC_API_KEY || "";
|
|
2451
|
+
const client = new import_sdk.default({
|
|
2452
|
+
apiKey
|
|
2453
|
+
});
|
|
2454
|
+
const conversationMessages = [{
|
|
2455
|
+
role: "user",
|
|
2456
|
+
content: messages.user
|
|
2457
|
+
}];
|
|
2458
|
+
let iterations = 0;
|
|
2459
|
+
let finalText = "";
|
|
2460
|
+
while (iterations < maxIterations) {
|
|
2461
|
+
iterations++;
|
|
2462
|
+
const response = await client.messages.create({
|
|
2463
|
+
model: modelName,
|
|
2464
|
+
max_tokens: options.maxTokens || 4e3,
|
|
2465
|
+
temperature: options.temperature,
|
|
2466
|
+
system: messages.sys,
|
|
2467
|
+
messages: conversationMessages,
|
|
2468
|
+
tools
|
|
2469
|
+
});
|
|
2470
|
+
if (response.stop_reason === "end_turn") {
|
|
2471
|
+
const textBlock = response.content.find((block) => block.type === "text");
|
|
2472
|
+
if (textBlock && textBlock.type === "text") {
|
|
2473
|
+
finalText = textBlock.text;
|
|
2474
|
+
if (options.partial) {
|
|
2475
|
+
options.partial(finalText);
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
break;
|
|
2479
|
+
}
|
|
2480
|
+
if (response.stop_reason === "tool_use") {
|
|
2481
|
+
const toolUses = response.content.filter((block) => block.type === "tool_use");
|
|
2482
|
+
if (toolUses.length === 0) {
|
|
2483
|
+
break;
|
|
2484
|
+
}
|
|
2485
|
+
conversationMessages.push({
|
|
2486
|
+
role: "assistant",
|
|
2487
|
+
content: response.content
|
|
2488
|
+
});
|
|
2489
|
+
const toolResults = {
|
|
2490
|
+
role: "user",
|
|
2491
|
+
content: []
|
|
2492
|
+
};
|
|
2493
|
+
for (const toolUse of toolUses) {
|
|
2494
|
+
if (toolUse.type === "tool_use") {
|
|
2495
|
+
try {
|
|
2496
|
+
const result = await toolHandler(toolUse.name, toolUse.input);
|
|
2497
|
+
toolResults.content.push({
|
|
2498
|
+
type: "tool_result",
|
|
2499
|
+
tool_use_id: toolUse.id,
|
|
2500
|
+
content: typeof result === "string" ? result : JSON.stringify(result)
|
|
2501
|
+
});
|
|
2502
|
+
} catch (error) {
|
|
2503
|
+
toolResults.content.push({
|
|
2504
|
+
type: "tool_result",
|
|
2505
|
+
tool_use_id: toolUse.id,
|
|
2506
|
+
content: error instanceof Error ? error.message : String(error),
|
|
2507
|
+
is_error: true
|
|
2508
|
+
});
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
conversationMessages.push(toolResults);
|
|
2513
|
+
} else {
|
|
2514
|
+
const textBlock = response.content.find((block) => block.type === "text");
|
|
2515
|
+
if (textBlock && textBlock.type === "text") {
|
|
2516
|
+
finalText = textBlock.text;
|
|
2517
|
+
if (options.partial) {
|
|
2518
|
+
options.partial(finalText);
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
break;
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
if (iterations >= maxIterations) {
|
|
2525
|
+
throw new Error(`Max iterations (${maxIterations}) reached in tool calling loop`);
|
|
2526
|
+
}
|
|
2527
|
+
return finalText;
|
|
2528
|
+
}
|
|
2385
2529
|
// ============================================================
|
|
2386
2530
|
// GROQ IMPLEMENTATION
|
|
2387
2531
|
// ============================================================
|
|
@@ -2994,62 +3138,460 @@ var BaseLLM = class {
|
|
|
2994
3138
|
throw error;
|
|
2995
3139
|
}
|
|
2996
3140
|
}
|
|
3141
|
+
/**
|
|
3142
|
+
* Match components from text response suggestions
|
|
3143
|
+
* Takes a text response with component suggestions (c1:type format) and matches with available components
|
|
3144
|
+
* @param textResponse - The text response containing component suggestions
|
|
3145
|
+
* @param components - List of available components
|
|
3146
|
+
* @param apiKey - Optional API key
|
|
3147
|
+
* @param logCollector - Optional log collector
|
|
3148
|
+
* @returns Object containing matched components, selected layout, and reasoning
|
|
3149
|
+
*/
|
|
3150
|
+
async matchComponentsFromTextResponse(textResponse, components, apiKey, logCollector) {
|
|
3151
|
+
try {
|
|
3152
|
+
logger.debug(`[${this.getProviderName()}] Starting component matching from text response`);
|
|
3153
|
+
let availableComponentsText = "No components available";
|
|
3154
|
+
if (components && components.length > 0) {
|
|
3155
|
+
availableComponentsText = components.map((comp, idx) => {
|
|
3156
|
+
const keywords = comp.keywords ? comp.keywords.join(", ") : "";
|
|
3157
|
+
const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
|
|
3158
|
+
return `${idx + 1}. ID: ${comp.id}
|
|
3159
|
+
Name: ${comp.name}
|
|
3160
|
+
Type: ${comp.type}
|
|
3161
|
+
Description: ${comp.description || "No description"}
|
|
3162
|
+
Keywords: ${keywords}
|
|
3163
|
+
Props Structure: ${propsPreview}`;
|
|
3164
|
+
}).join("\n\n");
|
|
3165
|
+
}
|
|
3166
|
+
const schemaDoc = schema.generateSchemaDocumentation();
|
|
3167
|
+
const prompts = await promptLoader.loadPrompts("match-text-components", {
|
|
3168
|
+
TEXT_RESPONSE: textResponse,
|
|
3169
|
+
AVAILABLE_COMPONENTS: availableComponentsText,
|
|
3170
|
+
SCHEMA_DOC: schemaDoc
|
|
3171
|
+
});
|
|
3172
|
+
logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
|
|
3173
|
+
logger.file("\n=============================\nmatch text components system prompt:", prompts.system);
|
|
3174
|
+
logCollector?.info("Matching components from text response...");
|
|
3175
|
+
const rawResponse = await LLM.stream(
|
|
3176
|
+
{
|
|
3177
|
+
sys: prompts.system,
|
|
3178
|
+
user: prompts.user
|
|
3179
|
+
},
|
|
3180
|
+
{
|
|
3181
|
+
model: this.model,
|
|
3182
|
+
maxTokens: 3e3,
|
|
3183
|
+
temperature: 0.2,
|
|
3184
|
+
apiKey: this.getApiKey(apiKey)
|
|
3185
|
+
},
|
|
3186
|
+
false
|
|
3187
|
+
// Don't parse as JSON yet, get raw response
|
|
3188
|
+
);
|
|
3189
|
+
logger.debug(`[${this.getProviderName()}] Raw component matching response length: ${rawResponse?.length || 0}`);
|
|
3190
|
+
logger.file(`[${this.getProviderName()}] Component matching raw response:`, rawResponse);
|
|
3191
|
+
let result;
|
|
3192
|
+
try {
|
|
3193
|
+
let cleanedResponse = rawResponse || "";
|
|
3194
|
+
cleanedResponse = cleanedResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
|
|
3195
|
+
const jsonMatch = cleanedResponse.match(/\{[\s\S]*\}/);
|
|
3196
|
+
if (jsonMatch) {
|
|
3197
|
+
cleanedResponse = jsonMatch[0];
|
|
3198
|
+
}
|
|
3199
|
+
result = JSON.parse(cleanedResponse);
|
|
3200
|
+
} catch (parseError) {
|
|
3201
|
+
logger.error(`[${this.getProviderName()}] Failed to parse component matching JSON response`);
|
|
3202
|
+
const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
|
|
3203
|
+
const posMatch = errorMsg.match(/position (\d+)/);
|
|
3204
|
+
const errorPos = posMatch ? parseInt(posMatch[1]) : -1;
|
|
3205
|
+
if (errorPos > 0 && rawResponse) {
|
|
3206
|
+
const start = Math.max(0, errorPos - 200);
|
|
3207
|
+
const end = Math.min(rawResponse.length, errorPos + 200);
|
|
3208
|
+
logger.debug(`[${this.getProviderName()}] Error context (position ${errorPos}):`);
|
|
3209
|
+
logger.debug(rawResponse.substring(start, end));
|
|
3210
|
+
logger.debug(" ".repeat(Math.min(200, errorPos - start)) + "^--- Error here");
|
|
3211
|
+
}
|
|
3212
|
+
logger.debug(`[${this.getProviderName()}] Raw response (first 2000 chars):`, rawResponse?.substring(0, 2e3));
|
|
3213
|
+
logger.debug(`[${this.getProviderName()}] Parse error:`, parseError);
|
|
3214
|
+
logCollector?.error(`Failed to parse component matching response: ${errorMsg}`);
|
|
3215
|
+
try {
|
|
3216
|
+
logger.info(`[${this.getProviderName()}] Attempting aggressive JSON cleanup...`);
|
|
3217
|
+
let aggressive = rawResponse || "";
|
|
3218
|
+
aggressive = aggressive.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
|
|
3219
|
+
const match = aggressive.match(/\{[\s\S]*\}/);
|
|
3220
|
+
if (match) {
|
|
3221
|
+
aggressive = match[0];
|
|
3222
|
+
}
|
|
3223
|
+
aggressive = aggressive.replace(/,(\s*[}\]])/g, "$1");
|
|
3224
|
+
result = JSON.parse(aggressive);
|
|
3225
|
+
logger.info(`[${this.getProviderName()}] Aggressive cleanup succeeded!`);
|
|
3226
|
+
} catch (secondError) {
|
|
3227
|
+
logger.error(`[${this.getProviderName()}] Aggressive cleanup also failed`);
|
|
3228
|
+
return {
|
|
3229
|
+
components: [],
|
|
3230
|
+
selectedLayout: "MultiComponentContainer",
|
|
3231
|
+
selectedLayoutId: "",
|
|
3232
|
+
selectedLayoutComponent: null,
|
|
3233
|
+
layoutReasoning: "No layout selected"
|
|
3234
|
+
};
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
const matchedComponents = result.matchedComponents || [];
|
|
3238
|
+
const selectedLayout = result.selectedLayout || "MultiComponentContainer";
|
|
3239
|
+
const selectedLayoutId = result.selectedLayoutId || "";
|
|
3240
|
+
const layoutReasoning = result.layoutReasoning || "No layout reasoning provided";
|
|
3241
|
+
let selectedLayoutComponent = null;
|
|
3242
|
+
if (selectedLayoutId) {
|
|
3243
|
+
selectedLayoutComponent = components.find((c) => c.id === selectedLayoutId) || null;
|
|
3244
|
+
if (!selectedLayoutComponent) {
|
|
3245
|
+
logger.warn(`[${this.getProviderName()}] Layout component ${selectedLayoutId} not found in available components`);
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
logger.info(`[${this.getProviderName()}] Matched ${matchedComponents.length} components from text response`);
|
|
3249
|
+
logger.info(`[${this.getProviderName()}] Selected layout: ${selectedLayout} (ID: ${selectedLayoutId})`);
|
|
3250
|
+
logger.info(`[${this.getProviderName()}] Layout reasoning: ${layoutReasoning}`);
|
|
3251
|
+
if (matchedComponents.length > 0) {
|
|
3252
|
+
logCollector?.info(`Matched ${matchedComponents.length} components for visualization using ${selectedLayout}`);
|
|
3253
|
+
logCollector?.info(`Layout reasoning: ${layoutReasoning}`);
|
|
3254
|
+
matchedComponents.forEach((comp, idx) => {
|
|
3255
|
+
logCollector?.info(` ${idx + 1}. ${comp.componentName} (${comp.componentType}): ${comp.reasoning}`);
|
|
3256
|
+
if (comp.props?.query) {
|
|
3257
|
+
logCollector?.logQuery(
|
|
3258
|
+
`Component ${idx + 1} query`,
|
|
3259
|
+
comp.props.query,
|
|
3260
|
+
{ componentName: comp.componentName, title: comp.props.title }
|
|
3261
|
+
);
|
|
3262
|
+
}
|
|
3263
|
+
});
|
|
3264
|
+
}
|
|
3265
|
+
const finalComponents = matchedComponents.map((mc) => {
|
|
3266
|
+
const originalComponent = components.find((c) => c.id === mc.componentId);
|
|
3267
|
+
if (!originalComponent) {
|
|
3268
|
+
logger.warn(`[${this.getProviderName()}] Component ${mc.componentId} not found in available components`);
|
|
3269
|
+
return null;
|
|
3270
|
+
}
|
|
3271
|
+
return {
|
|
3272
|
+
...originalComponent,
|
|
3273
|
+
props: {
|
|
3274
|
+
...originalComponent.props,
|
|
3275
|
+
...mc.props
|
|
3276
|
+
}
|
|
3277
|
+
};
|
|
3278
|
+
}).filter(Boolean);
|
|
3279
|
+
return {
|
|
3280
|
+
components: finalComponents,
|
|
3281
|
+
selectedLayout,
|
|
3282
|
+
selectedLayoutId,
|
|
3283
|
+
selectedLayoutComponent,
|
|
3284
|
+
layoutReasoning
|
|
3285
|
+
};
|
|
3286
|
+
} catch (error) {
|
|
3287
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3288
|
+
logger.error(`[${this.getProviderName()}] Error matching components from text response: ${errorMsg}`);
|
|
3289
|
+
logger.debug(`[${this.getProviderName()}] Component matching error details:`, error);
|
|
3290
|
+
logCollector?.error(`Error matching components: ${errorMsg}`);
|
|
3291
|
+
return {
|
|
3292
|
+
components: [],
|
|
3293
|
+
selectedLayout: "MultiComponentContainer",
|
|
3294
|
+
selectedLayoutId: "",
|
|
3295
|
+
selectedLayoutComponent: null,
|
|
3296
|
+
layoutReasoning: "Error occurred during component matching"
|
|
3297
|
+
};
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
2997
3300
|
/**
|
|
2998
3301
|
* Generate text-based response for user question
|
|
2999
3302
|
* This provides conversational text responses instead of component generation
|
|
3303
|
+
* Supports tool calling for query execution with automatic retry on errors (max 3 attempts)
|
|
3304
|
+
* After generating text response, if components are provided, matches suggested components
|
|
3305
|
+
* @param streamCallback - Optional callback function to receive text chunks as they stream
|
|
3306
|
+
* @param collections - Collection registry for executing database queries via database.execute
|
|
3307
|
+
* @param components - Optional list of available components for matching suggestions
|
|
3000
3308
|
*/
|
|
3001
|
-
async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory) {
|
|
3309
|
+
async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory, streamCallback, collections, components) {
|
|
3002
3310
|
const errors = [];
|
|
3003
3311
|
logger.debug(`[${this.getProviderName()}] Starting text response generation`);
|
|
3004
3312
|
logger.debug(`[${this.getProviderName()}] User prompt: "${userPrompt.substring(0, 50)}..."`);
|
|
3005
3313
|
try {
|
|
3314
|
+
const schemaDoc = schema.generateSchemaDocumentation();
|
|
3006
3315
|
const prompts = await promptLoader.loadPrompts("text-response", {
|
|
3007
3316
|
USER_PROMPT: userPrompt,
|
|
3008
|
-
CONVERSATION_HISTORY: conversationHistory || "No previous conversation"
|
|
3317
|
+
CONVERSATION_HISTORY: conversationHistory || "No previous conversation",
|
|
3318
|
+
SCHEMA_DOC: schemaDoc
|
|
3009
3319
|
});
|
|
3010
|
-
logger.
|
|
3320
|
+
logger.file("\n=============================\nsystem prompt:", prompts.system);
|
|
3321
|
+
logger.file("\n=============================\nuser prompt:", prompts.user);
|
|
3322
|
+
logger.debug(`[${this.getProviderName()}] Loaded text-response prompts with schema`);
|
|
3011
3323
|
logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
|
|
3012
|
-
logCollector?.info("Generating text response...");
|
|
3013
|
-
const
|
|
3324
|
+
logCollector?.info("Generating text response with query execution capability...");
|
|
3325
|
+
const tools = [{
|
|
3326
|
+
name: "execute_query",
|
|
3327
|
+
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.",
|
|
3328
|
+
input_schema: {
|
|
3329
|
+
type: "object",
|
|
3330
|
+
properties: {
|
|
3331
|
+
query: {
|
|
3332
|
+
type: "string",
|
|
3333
|
+
description: "The SQL query to execute. Must be valid SQL syntax using table and column names from the schema."
|
|
3334
|
+
},
|
|
3335
|
+
reasoning: {
|
|
3336
|
+
type: "string",
|
|
3337
|
+
description: "Brief explanation of what this query does and why it answers the user's question."
|
|
3338
|
+
}
|
|
3339
|
+
},
|
|
3340
|
+
required: ["query"]
|
|
3341
|
+
}
|
|
3342
|
+
}];
|
|
3343
|
+
const queryAttempts = /* @__PURE__ */ new Map();
|
|
3344
|
+
const MAX_QUERY_ATTEMPTS = 6;
|
|
3345
|
+
let maxAttemptsReached = false;
|
|
3346
|
+
let fullStreamedText = "";
|
|
3347
|
+
const wrappedStreamCallback = streamCallback ? (chunk) => {
|
|
3348
|
+
fullStreamedText += chunk;
|
|
3349
|
+
streamCallback(chunk);
|
|
3350
|
+
} : void 0;
|
|
3351
|
+
const toolHandler = async (toolName, toolInput) => {
|
|
3352
|
+
if (toolName === "execute_query") {
|
|
3353
|
+
let query = toolInput.query;
|
|
3354
|
+
const reasoning = toolInput.reasoning;
|
|
3355
|
+
const { ensureQueryLimit: ensureQueryLimit2 } = await Promise.resolve().then(() => (init_utils(), utils_exports));
|
|
3356
|
+
query = ensureQueryLimit2(query, 32, 32);
|
|
3357
|
+
const queryKey = query.toLowerCase().replace(/\s+/g, " ").trim();
|
|
3358
|
+
const attempts = (queryAttempts.get(queryKey) || 0) + 1;
|
|
3359
|
+
queryAttempts.set(queryKey, attempts);
|
|
3360
|
+
logger.info(`[${this.getProviderName()}] Executing query (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${query.substring(0, 100)}...`);
|
|
3361
|
+
if (reasoning) {
|
|
3362
|
+
logCollector?.info(`Query reasoning: ${reasoning}`);
|
|
3363
|
+
}
|
|
3364
|
+
if (attempts > MAX_QUERY_ATTEMPTS) {
|
|
3365
|
+
const errorMsg = `Maximum query attempts (${MAX_QUERY_ATTEMPTS}) reached. Unable to generate a valid query for your question.`;
|
|
3366
|
+
logger.error(`[${this.getProviderName()}] ${errorMsg}`);
|
|
3367
|
+
logCollector?.error(errorMsg);
|
|
3368
|
+
maxAttemptsReached = true;
|
|
3369
|
+
if (wrappedStreamCallback) {
|
|
3370
|
+
wrappedStreamCallback(`
|
|
3371
|
+
|
|
3372
|
+
\u274C ${errorMsg}
|
|
3373
|
+
|
|
3374
|
+
Please try rephrasing your question or simplifying your request.
|
|
3375
|
+
|
|
3376
|
+
`);
|
|
3377
|
+
}
|
|
3378
|
+
throw new Error(errorMsg);
|
|
3379
|
+
}
|
|
3380
|
+
try {
|
|
3381
|
+
if (wrappedStreamCallback) {
|
|
3382
|
+
if (attempts === 1) {
|
|
3383
|
+
wrappedStreamCallback(`
|
|
3384
|
+
|
|
3385
|
+
\u{1F50D} **Analyzing your question...**
|
|
3386
|
+
|
|
3387
|
+
`);
|
|
3388
|
+
if (reasoning) {
|
|
3389
|
+
wrappedStreamCallback(`\u{1F4AD} ${reasoning}
|
|
3390
|
+
|
|
3391
|
+
`);
|
|
3392
|
+
}
|
|
3393
|
+
wrappedStreamCallback(`\u{1F4DD} **Generated SQL Query:**
|
|
3394
|
+
\`\`\`sql
|
|
3395
|
+
${query}
|
|
3396
|
+
\`\`\`
|
|
3397
|
+
|
|
3398
|
+
`);
|
|
3399
|
+
wrappedStreamCallback(`\u26A1 **Executing query...**
|
|
3400
|
+
|
|
3401
|
+
`);
|
|
3402
|
+
} else {
|
|
3403
|
+
wrappedStreamCallback(`
|
|
3404
|
+
|
|
3405
|
+
\u{1F504} **Retrying with corrected query (attempt ${attempts}/${MAX_QUERY_ATTEMPTS})...**
|
|
3406
|
+
|
|
3407
|
+
`);
|
|
3408
|
+
if (reasoning) {
|
|
3409
|
+
wrappedStreamCallback(`\u{1F4AD} ${reasoning}
|
|
3410
|
+
|
|
3411
|
+
`);
|
|
3412
|
+
}
|
|
3413
|
+
wrappedStreamCallback(`\u{1F4DD} **Corrected SQL Query:**
|
|
3414
|
+
\`\`\`sql
|
|
3415
|
+
${query}
|
|
3416
|
+
\`\`\`
|
|
3417
|
+
|
|
3418
|
+
`);
|
|
3419
|
+
wrappedStreamCallback(`\u26A1 **Executing query...**
|
|
3420
|
+
|
|
3421
|
+
`);
|
|
3422
|
+
}
|
|
3423
|
+
}
|
|
3424
|
+
logCollector?.logQuery(
|
|
3425
|
+
`Executing SQL query (attempt ${attempts})`,
|
|
3426
|
+
query,
|
|
3427
|
+
{ reasoning, attempt: attempts }
|
|
3428
|
+
);
|
|
3429
|
+
if (!collections || !collections["database"] || !collections["database"]["execute"]) {
|
|
3430
|
+
throw new Error("Database collection not registered. Please register database.execute collection to execute queries.");
|
|
3431
|
+
}
|
|
3432
|
+
const result2 = await collections["database"]["execute"]({ sql: query });
|
|
3433
|
+
const data = result2?.data || result2;
|
|
3434
|
+
const rowCount = result2?.count ?? (Array.isArray(data) ? data.length : "N/A");
|
|
3435
|
+
logger.info(`[${this.getProviderName()}] Query executed successfully, rows returned: ${rowCount}`);
|
|
3436
|
+
logCollector?.info(`Query successful, returned ${rowCount} rows`);
|
|
3437
|
+
if (wrappedStreamCallback) {
|
|
3438
|
+
wrappedStreamCallback(`\u2705 **Query executed successfully!**
|
|
3439
|
+
|
|
3440
|
+
`);
|
|
3441
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
3442
|
+
const firstRow = data[0];
|
|
3443
|
+
const columns = Object.keys(firstRow);
|
|
3444
|
+
if (data.length === 1 && columns.length === 1) {
|
|
3445
|
+
const value = firstRow[columns[0]];
|
|
3446
|
+
wrappedStreamCallback(`**Result:** ${value}
|
|
3447
|
+
|
|
3448
|
+
`);
|
|
3449
|
+
} else if (data.length > 0) {
|
|
3450
|
+
wrappedStreamCallback(`**Retrieved ${rowCount} rows**
|
|
3451
|
+
|
|
3452
|
+
`);
|
|
3453
|
+
wrappedStreamCallback(`<DataTable>${JSON.stringify(data)}</DataTable>
|
|
3454
|
+
|
|
3455
|
+
`);
|
|
3456
|
+
}
|
|
3457
|
+
} else if (Array.isArray(data) && data.length === 0) {
|
|
3458
|
+
wrappedStreamCallback(`**No rows returned.**
|
|
3459
|
+
|
|
3460
|
+
`);
|
|
3461
|
+
}
|
|
3462
|
+
wrappedStreamCallback(`\u{1F4CA} **Analyzing results...**
|
|
3463
|
+
|
|
3464
|
+
`);
|
|
3465
|
+
}
|
|
3466
|
+
return JSON.stringify(data, null, 2);
|
|
3467
|
+
} catch (error) {
|
|
3468
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3469
|
+
logger.error(`[${this.getProviderName()}] Query execution failed (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${errorMsg}`);
|
|
3470
|
+
logCollector?.error(`Query failed (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${errorMsg}`);
|
|
3471
|
+
if (wrappedStreamCallback) {
|
|
3472
|
+
wrappedStreamCallback(`\u274C **Query execution failed:**
|
|
3473
|
+
\`\`\`
|
|
3474
|
+
${errorMsg}
|
|
3475
|
+
\`\`\`
|
|
3476
|
+
|
|
3477
|
+
`);
|
|
3478
|
+
if (attempts < MAX_QUERY_ATTEMPTS) {
|
|
3479
|
+
wrappedStreamCallback(`\u{1F527} **Generating corrected query...**
|
|
3480
|
+
|
|
3481
|
+
`);
|
|
3482
|
+
}
|
|
3483
|
+
}
|
|
3484
|
+
throw new Error(`Query execution failed: ${errorMsg}`);
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
throw new Error(`Unknown tool: ${toolName}`);
|
|
3488
|
+
};
|
|
3489
|
+
const result = await LLM.streamWithTools(
|
|
3014
3490
|
{
|
|
3015
3491
|
sys: prompts.system,
|
|
3016
3492
|
user: prompts.user
|
|
3017
3493
|
},
|
|
3494
|
+
tools,
|
|
3495
|
+
toolHandler,
|
|
3018
3496
|
{
|
|
3019
3497
|
model: this.model,
|
|
3020
|
-
maxTokens:
|
|
3498
|
+
maxTokens: 4e3,
|
|
3021
3499
|
temperature: 0.7,
|
|
3022
|
-
apiKey: this.getApiKey(apiKey)
|
|
3500
|
+
apiKey: this.getApiKey(apiKey),
|
|
3501
|
+
partial: wrappedStreamCallback
|
|
3502
|
+
// Pass the wrapped streaming callback to LLM
|
|
3023
3503
|
},
|
|
3024
|
-
|
|
3025
|
-
//
|
|
3504
|
+
10
|
|
3505
|
+
// max iterations: allows for 6 retries + final response + buffer
|
|
3026
3506
|
);
|
|
3027
|
-
logger.info(`[${this.getProviderName()}] Text response
|
|
3028
|
-
|
|
3029
|
-
|
|
3507
|
+
logger.info(`[${this.getProviderName()}] Text response stream completed`);
|
|
3508
|
+
const textResponse = fullStreamedText || result || "I apologize, but I was unable to generate a response.";
|
|
3509
|
+
if (maxAttemptsReached) {
|
|
3510
|
+
logger.warn(`[${this.getProviderName()}] Max query attempts reached, returning failure response`);
|
|
3511
|
+
logCollector?.error("Failed to generate valid query after maximum attempts");
|
|
3512
|
+
return {
|
|
3513
|
+
success: false,
|
|
3514
|
+
errors: [`Maximum query attempts (${MAX_QUERY_ATTEMPTS}) reached. Unable to generate a valid query for your question.`],
|
|
3515
|
+
data: {
|
|
3516
|
+
text: textResponse,
|
|
3517
|
+
// Include the streamed text showing all attempts
|
|
3518
|
+
matchedComponents: [],
|
|
3519
|
+
method: `${this.getProviderName()}-text-response-max-attempts`
|
|
3520
|
+
}
|
|
3521
|
+
};
|
|
3522
|
+
}
|
|
3523
|
+
logCollector?.info(`Text response: ${textResponse.substring(0, 100)}${textResponse.length > 100 ? "..." : ""}`);
|
|
3030
3524
|
logCollector?.logExplanation(
|
|
3031
3525
|
"Text response generated",
|
|
3032
|
-
|
|
3526
|
+
"Generated plain text response with component suggestions",
|
|
3033
3527
|
{
|
|
3034
|
-
|
|
3035
|
-
confidence: result.confidence,
|
|
3036
|
-
textLength: result.text?.length || 0
|
|
3528
|
+
textLength: textResponse.length
|
|
3037
3529
|
}
|
|
3038
3530
|
);
|
|
3531
|
+
let matchedComponents = [];
|
|
3532
|
+
let selectedLayoutComponent = null;
|
|
3533
|
+
let layoutReasoning = "No layout selected";
|
|
3534
|
+
if (components && components.length > 0) {
|
|
3535
|
+
logger.info(`[${this.getProviderName()}] Matching components from text response...`);
|
|
3536
|
+
const matchResult = await this.matchComponentsFromTextResponse(
|
|
3537
|
+
textResponse,
|
|
3538
|
+
components,
|
|
3539
|
+
apiKey,
|
|
3540
|
+
logCollector
|
|
3541
|
+
);
|
|
3542
|
+
matchedComponents = matchResult.components;
|
|
3543
|
+
selectedLayoutComponent = matchResult.selectedLayoutComponent;
|
|
3544
|
+
layoutReasoning = matchResult.layoutReasoning;
|
|
3545
|
+
}
|
|
3546
|
+
let container_componet = null;
|
|
3547
|
+
if (matchedComponents.length > 0) {
|
|
3548
|
+
if (selectedLayoutComponent) {
|
|
3549
|
+
container_componet = {
|
|
3550
|
+
...selectedLayoutComponent,
|
|
3551
|
+
id: `${selectedLayoutComponent.id}_${Date.now()}`,
|
|
3552
|
+
description: layoutReasoning,
|
|
3553
|
+
props: {
|
|
3554
|
+
...selectedLayoutComponent.props,
|
|
3555
|
+
config: {
|
|
3556
|
+
...selectedLayoutComponent.props?.config || {},
|
|
3557
|
+
components: matchedComponents
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
};
|
|
3561
|
+
logger.info(`[${this.getProviderName()}] Created ${selectedLayoutComponent.name} (${selectedLayoutComponent.type}) container with ${matchedComponents.length} components`);
|
|
3562
|
+
logCollector?.info(`Created ${selectedLayoutComponent.name} with ${matchedComponents.length} components: ${layoutReasoning}`);
|
|
3563
|
+
} else {
|
|
3564
|
+
container_componet = {
|
|
3565
|
+
id: `multi_container_${Date.now()}`,
|
|
3566
|
+
name: "MultiComponentContainer",
|
|
3567
|
+
type: "Container",
|
|
3568
|
+
description: layoutReasoning,
|
|
3569
|
+
category: "dynamic",
|
|
3570
|
+
keywords: ["dashboard", "layout", "container"],
|
|
3571
|
+
props: {
|
|
3572
|
+
config: {
|
|
3573
|
+
components: matchedComponents
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
};
|
|
3577
|
+
logger.info(`[${this.getProviderName()}] Created fallback MultiComponentContainer with ${matchedComponents.length} components`);
|
|
3578
|
+
logCollector?.info(`Created MultiComponentContainer with ${matchedComponents.length} components: ${layoutReasoning}`);
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3039
3581
|
return {
|
|
3040
3582
|
success: true,
|
|
3041
3583
|
data: {
|
|
3042
|
-
text:
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3584
|
+
text: textResponse,
|
|
3585
|
+
matchedComponents,
|
|
3586
|
+
component: container_componet,
|
|
3587
|
+
layoutReasoning,
|
|
3588
|
+
method: `${this.getProviderName()}-text-response`
|
|
3046
3589
|
},
|
|
3047
3590
|
errors: []
|
|
3048
3591
|
};
|
|
3049
3592
|
} catch (error) {
|
|
3050
3593
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3051
3594
|
logger.error(`[${this.getProviderName()}] Error generating text response: ${errorMsg}`);
|
|
3052
|
-
logger.debug(`[${this.getProviderName()}] Text response generation error details:`, error);
|
|
3053
3595
|
logCollector?.error(`Error generating text response: ${errorMsg}`);
|
|
3054
3596
|
errors.push(errorMsg);
|
|
3055
3597
|
return {
|
|
@@ -3057,9 +3599,8 @@ var BaseLLM = class {
|
|
|
3057
3599
|
errors,
|
|
3058
3600
|
data: {
|
|
3059
3601
|
text: "I apologize, but I encountered an error while processing your question. Please try rephrasing or ask something else.",
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
reasoning: `Error: ${errorMsg}`
|
|
3602
|
+
matchedComponents: [],
|
|
3603
|
+
method: `${this.getProviderName()}-text-response-error`
|
|
3063
3604
|
}
|
|
3064
3605
|
};
|
|
3065
3606
|
}
|
|
@@ -3250,8 +3791,11 @@ var BaseLLM = class {
|
|
|
3250
3791
|
* Supports both component generation and text response modes
|
|
3251
3792
|
*
|
|
3252
3793
|
* @param responseMode - 'component' for component generation (default), 'text' for text responses
|
|
3794
|
+
* @param streamCallback - Optional callback function to receive text chunks as they stream (only for text mode)
|
|
3795
|
+
* @param collections - Collection registry for executing database queries (required for text mode)
|
|
3253
3796
|
*/
|
|
3254
|
-
async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") {
|
|
3797
|
+
async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) {
|
|
3798
|
+
const startTime = Date.now();
|
|
3255
3799
|
logger.info(`[${this.getProviderName()}] handleUserRequest called with responseMode: ${responseMode}`);
|
|
3256
3800
|
if (responseMode === "text") {
|
|
3257
3801
|
logger.info(`[${this.getProviderName()}] Using text response mode`);
|
|
@@ -3260,25 +3804,23 @@ var BaseLLM = class {
|
|
|
3260
3804
|
userPrompt,
|
|
3261
3805
|
apiKey,
|
|
3262
3806
|
logCollector,
|
|
3263
|
-
conversationHistory
|
|
3807
|
+
conversationHistory,
|
|
3808
|
+
streamCallback,
|
|
3809
|
+
collections,
|
|
3810
|
+
components
|
|
3264
3811
|
);
|
|
3265
3812
|
if (!textResponse.success) {
|
|
3813
|
+
const elapsedTime3 = Date.now() - startTime;
|
|
3266
3814
|
logger.error(`[${this.getProviderName()}] Text response generation failed`);
|
|
3815
|
+
logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime3}ms (${(elapsedTime3 / 1e3).toFixed(2)}s)`);
|
|
3816
|
+
logCollector?.info(`Total time taken: ${elapsedTime3}ms (${(elapsedTime3 / 1e3).toFixed(2)}s)`);
|
|
3267
3817
|
return textResponse;
|
|
3268
3818
|
}
|
|
3819
|
+
const elapsedTime2 = Date.now() - startTime;
|
|
3269
3820
|
logger.info(`[${this.getProviderName()}] Text response generated successfully`);
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
textResponse: textResponse.data.text,
|
|
3274
|
-
text: textResponse.data.text,
|
|
3275
|
-
responseType: textResponse.data.responseType,
|
|
3276
|
-
confidence: textResponse.data.confidence,
|
|
3277
|
-
reasoning: textResponse.data.reasoning,
|
|
3278
|
-
method: `${this.getProviderName()}-text-response`
|
|
3279
|
-
},
|
|
3280
|
-
errors: []
|
|
3281
|
-
};
|
|
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)`);
|
|
3823
|
+
return textResponse;
|
|
3282
3824
|
}
|
|
3283
3825
|
const componentResponse = await this.generateComponentResponse(
|
|
3284
3826
|
userPrompt,
|
|
@@ -3288,24 +3830,17 @@ var BaseLLM = class {
|
|
|
3288
3830
|
conversationHistory
|
|
3289
3831
|
);
|
|
3290
3832
|
if (!componentResponse.success) {
|
|
3833
|
+
const elapsedTime2 = Date.now() - startTime;
|
|
3291
3834
|
logger.error(`[${this.getProviderName()}] Component response generation failed`);
|
|
3835
|
+
logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
|
|
3836
|
+
logCollector?.info(`Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
|
|
3292
3837
|
return componentResponse;
|
|
3293
3838
|
}
|
|
3839
|
+
const elapsedTime = Date.now() - startTime;
|
|
3294
3840
|
logger.info(`[${this.getProviderName()}] Component response generated successfully`);
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
component: componentResponse.data.component,
|
|
3299
|
-
reasoning: componentResponse.data.reasoning,
|
|
3300
|
-
method: componentResponse.data.method,
|
|
3301
|
-
// Preserve the original method name
|
|
3302
|
-
questionType: componentResponse.data.questionType,
|
|
3303
|
-
needsMultipleComponents: componentResponse.data.needsMultipleComponents,
|
|
3304
|
-
propsModified: componentResponse.data.propsModified,
|
|
3305
|
-
queryModified: componentResponse.data.queryModified
|
|
3306
|
-
},
|
|
3307
|
-
errors: []
|
|
3308
|
-
};
|
|
3841
|
+
logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
|
|
3842
|
+
logCollector?.info(`Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
|
|
3843
|
+
return componentResponse;
|
|
3309
3844
|
}
|
|
3310
3845
|
/**
|
|
3311
3846
|
* Generate next questions that the user might ask based on the original prompt and generated component
|
|
@@ -3418,7 +3953,7 @@ function getLLMProviders() {
|
|
|
3418
3953
|
return DEFAULT_PROVIDERS;
|
|
3419
3954
|
}
|
|
3420
3955
|
}
|
|
3421
|
-
var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") => {
|
|
3956
|
+
var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) => {
|
|
3422
3957
|
logger.debug("[useAnthropicMethod] Initializing Anthropic Claude matching method");
|
|
3423
3958
|
logger.debug(`[useAnthropicMethod] Response mode: ${responseMode}`);
|
|
3424
3959
|
const msg = `Using Anthropic Claude ${responseMode === "text" ? "text response" : "matching"} method...`;
|
|
@@ -3430,11 +3965,11 @@ var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conver
|
|
|
3430
3965
|
return { success: false, errors: [emptyMsg] };
|
|
3431
3966
|
}
|
|
3432
3967
|
logger.debug(`[useAnthropicMethod] Processing with ${components.length} components`);
|
|
3433
|
-
const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode);
|
|
3968
|
+
const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
3434
3969
|
logger.info(`[useAnthropicMethod] Successfully generated ${responseMode} using Anthropic`);
|
|
3435
3970
|
return matchResult;
|
|
3436
3971
|
};
|
|
3437
|
-
var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component") => {
|
|
3972
|
+
var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) => {
|
|
3438
3973
|
logger.debug("[useGroqMethod] Initializing Groq LLM matching method");
|
|
3439
3974
|
logger.debug(`[useGroqMethod] Response mode: ${responseMode}`);
|
|
3440
3975
|
const msg = `Using Groq LLM ${responseMode === "text" ? "text response" : "matching"} method...`;
|
|
@@ -3447,16 +3982,16 @@ var useGroqMethod = async (prompt, components, apiKey, logCollector, conversatio
|
|
|
3447
3982
|
return { success: false, errors: [emptyMsg] };
|
|
3448
3983
|
}
|
|
3449
3984
|
logger.debug(`[useGroqMethod] Processing with ${components.length} components`);
|
|
3450
|
-
const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode);
|
|
3985
|
+
const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
3451
3986
|
logger.info(`[useGroqMethod] Successfully generated ${responseMode} using Groq`);
|
|
3452
3987
|
return matchResult;
|
|
3453
3988
|
};
|
|
3454
3989
|
var getUserResponseFromCache = async (prompt) => {
|
|
3455
3990
|
return false;
|
|
3456
3991
|
};
|
|
3457
|
-
var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory) => {
|
|
3458
|
-
const responseMode = "component";
|
|
3992
|
+
var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) => {
|
|
3459
3993
|
logger.debug(`[get_user_response] Starting user response generation for prompt: "${prompt.substring(0, 50)}..."`);
|
|
3994
|
+
logger.debug(`[get_user_response] Response mode: ${responseMode}`);
|
|
3460
3995
|
logger.debug("[get_user_response] Checking cache for existing response");
|
|
3461
3996
|
const userResponse = await getUserResponseFromCache(prompt);
|
|
3462
3997
|
if (userResponse) {
|
|
@@ -3487,16 +4022,16 @@ var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey,
|
|
|
3487
4022
|
logCollector?.info(attemptMsg);
|
|
3488
4023
|
let result;
|
|
3489
4024
|
if (provider === "anthropic") {
|
|
3490
|
-
result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory, responseMode);
|
|
4025
|
+
result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
3491
4026
|
} else if (provider === "groq") {
|
|
3492
|
-
result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory, responseMode);
|
|
4027
|
+
result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
3493
4028
|
} else {
|
|
3494
4029
|
logger.warn(`[get_user_response] Unknown provider: ${provider} - skipping`);
|
|
3495
4030
|
errors.push(`Unknown provider: ${provider}`);
|
|
3496
4031
|
continue;
|
|
3497
4032
|
}
|
|
3498
4033
|
if (result.success) {
|
|
3499
|
-
const successMsg = `Success with provider: ${provider}
|
|
4034
|
+
const successMsg = `Success with provider: ${provider}`;
|
|
3500
4035
|
logger.info(`${successMsg}`);
|
|
3501
4036
|
logCollector?.info(successMsg);
|
|
3502
4037
|
return result;
|
|
@@ -3717,8 +4252,7 @@ var CONTEXT_CONFIG = {
|
|
|
3717
4252
|
};
|
|
3718
4253
|
|
|
3719
4254
|
// src/handlers/user-prompt-request.ts
|
|
3720
|
-
var
|
|
3721
|
-
var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders) => {
|
|
4255
|
+
var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections) => {
|
|
3722
4256
|
const errors = [];
|
|
3723
4257
|
logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
|
|
3724
4258
|
const parseResult = UserPromptRequestMessageSchema.safeParse(data);
|
|
@@ -3734,19 +4268,6 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3734
4268
|
const prompt = payload.prompt;
|
|
3735
4269
|
const SA_RUNTIME = payload.SA_RUNTIME;
|
|
3736
4270
|
const wsId = userPromptRequest.from.id || "unknown";
|
|
3737
|
-
logger.debug(`[REQUEST ${id}] Full request details - wsId: ${wsId}, prompt length: ${prompt.length}`);
|
|
3738
|
-
if (processedMessageIds.has(id)) {
|
|
3739
|
-
logger.warn(`[REQUEST ${id}] Duplicate request detected - ignoring`);
|
|
3740
|
-
}
|
|
3741
|
-
processedMessageIds.add(id);
|
|
3742
|
-
logger.debug(`[REQUEST ${id}] Message ID marked as processed (${processedMessageIds.size} total)`);
|
|
3743
|
-
if (processedMessageIds.size > 100) {
|
|
3744
|
-
const firstId = processedMessageIds.values().next().value;
|
|
3745
|
-
if (firstId) {
|
|
3746
|
-
processedMessageIds.delete(firstId);
|
|
3747
|
-
logger.debug(`[REQUEST ${id}] Cleaned up old message ID from cache`);
|
|
3748
|
-
}
|
|
3749
|
-
}
|
|
3750
4271
|
if (!SA_RUNTIME) {
|
|
3751
4272
|
errors.push("SA_RUNTIME is required");
|
|
3752
4273
|
}
|
|
@@ -3761,9 +4282,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3761
4282
|
if (!prompt) {
|
|
3762
4283
|
errors.push("Prompt not found");
|
|
3763
4284
|
}
|
|
3764
|
-
|
|
3765
|
-
errors.push("Components not found");
|
|
3766
|
-
}
|
|
4285
|
+
logger.debug(`[REQUEST ${id}] Full request details - uiBlockId: ${existingUiBlockId}, threadId: ${threadId}, prompt: ${prompt}`);
|
|
3767
4286
|
if (errors.length > 0) {
|
|
3768
4287
|
return { success: false, errors, id, wsId };
|
|
3769
4288
|
}
|
|
@@ -3777,8 +4296,44 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3777
4296
|
logCollector.info(`Starting user prompt request with ${components.length} components`);
|
|
3778
4297
|
const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
|
|
3779
4298
|
logger.info("conversationHistory", conversationHistory);
|
|
3780
|
-
const
|
|
3781
|
-
logger.info("
|
|
4299
|
+
const responseMode = payload.responseMode || "component";
|
|
4300
|
+
logger.info("responseMode", responseMode);
|
|
4301
|
+
let streamCallback;
|
|
4302
|
+
let accumulatedStreamResponse = "";
|
|
4303
|
+
if (responseMode === "text") {
|
|
4304
|
+
streamCallback = (chunk) => {
|
|
4305
|
+
accumulatedStreamResponse += chunk;
|
|
4306
|
+
logger.debug(`[STREAM] Sending chunk (${chunk.length} chars): "${chunk.substring(0, 20)}..."`);
|
|
4307
|
+
const streamMessage = {
|
|
4308
|
+
id: `stream_${existingUiBlockId}`,
|
|
4309
|
+
// Different ID pattern for streaming
|
|
4310
|
+
type: "USER_PROMPT_STREAM",
|
|
4311
|
+
from: { type: "data-agent" },
|
|
4312
|
+
to: {
|
|
4313
|
+
type: "runtime",
|
|
4314
|
+
id: wsId
|
|
4315
|
+
},
|
|
4316
|
+
payload: {
|
|
4317
|
+
uiBlockId: existingUiBlockId,
|
|
4318
|
+
chunk
|
|
4319
|
+
}
|
|
4320
|
+
};
|
|
4321
|
+
sendMessage(streamMessage);
|
|
4322
|
+
logger.debug(`[STREAM] Chunk sent to wsId: ${wsId}`);
|
|
4323
|
+
};
|
|
4324
|
+
}
|
|
4325
|
+
const userResponse = await get_user_response(
|
|
4326
|
+
prompt,
|
|
4327
|
+
components,
|
|
4328
|
+
anthropicApiKey,
|
|
4329
|
+
groqApiKey,
|
|
4330
|
+
llmProviders,
|
|
4331
|
+
logCollector,
|
|
4332
|
+
conversationHistory,
|
|
4333
|
+
responseMode,
|
|
4334
|
+
streamCallback,
|
|
4335
|
+
collections
|
|
4336
|
+
);
|
|
3782
4337
|
logCollector.info("User prompt request completed");
|
|
3783
4338
|
const uiBlockId = existingUiBlockId;
|
|
3784
4339
|
if (!userResponse.success) {
|
|
@@ -3801,10 +4356,11 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3801
4356
|
component = userResponse.data.component;
|
|
3802
4357
|
}
|
|
3803
4358
|
if ("textResponse" in userResponse.data) {
|
|
3804
|
-
textResponse = userResponse.data.
|
|
4359
|
+
textResponse = userResponse.data.text;
|
|
3805
4360
|
}
|
|
3806
4361
|
}
|
|
3807
4362
|
}
|
|
4363
|
+
const finalTextResponse = responseMode === "text" && accumulatedStreamResponse ? accumulatedStreamResponse : textResponse;
|
|
3808
4364
|
const uiBlock = new UIBlock(
|
|
3809
4365
|
prompt,
|
|
3810
4366
|
{},
|
|
@@ -3814,8 +4370,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3814
4370
|
[],
|
|
3815
4371
|
// actions: empty initially
|
|
3816
4372
|
uiBlockId,
|
|
3817
|
-
|
|
3818
|
-
// textResponse:
|
|
4373
|
+
finalTextResponse
|
|
4374
|
+
// textResponse: FULL streaming response including all intermediate messages
|
|
3819
4375
|
);
|
|
3820
4376
|
thread.addUIBlock(uiBlock);
|
|
3821
4377
|
logger.info(`Created UIBlock: ${uiBlockId} in Thread: ${threadId}`);
|
|
@@ -3829,8 +4385,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
3829
4385
|
wsId
|
|
3830
4386
|
};
|
|
3831
4387
|
};
|
|
3832
|
-
async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders) {
|
|
3833
|
-
const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders);
|
|
4388
|
+
async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections) {
|
|
4389
|
+
const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections);
|
|
3834
4390
|
sendDataResponse4(
|
|
3835
4391
|
response.id || data.id,
|
|
3836
4392
|
{
|
|
@@ -4906,7 +5462,7 @@ function sendResponse5(id, res, sendMessage, clientId) {
|
|
|
4906
5462
|
}
|
|
4907
5463
|
|
|
4908
5464
|
// src/auth/user-manager.ts
|
|
4909
|
-
var
|
|
5465
|
+
var import_fs4 = __toESM(require("fs"));
|
|
4910
5466
|
var import_path3 = __toESM(require("path"));
|
|
4911
5467
|
var import_os = __toESM(require("os"));
|
|
4912
5468
|
var UserManager = class {
|
|
@@ -4946,19 +5502,19 @@ var UserManager = class {
|
|
|
4946
5502
|
async loadUsersFromFile() {
|
|
4947
5503
|
try {
|
|
4948
5504
|
const dir = import_path3.default.dirname(this.filePath);
|
|
4949
|
-
if (!
|
|
5505
|
+
if (!import_fs4.default.existsSync(dir)) {
|
|
4950
5506
|
logger.info(`Creating directory structure: ${dir}`);
|
|
4951
|
-
|
|
5507
|
+
import_fs4.default.mkdirSync(dir, { recursive: true });
|
|
4952
5508
|
}
|
|
4953
|
-
if (!
|
|
5509
|
+
if (!import_fs4.default.existsSync(this.filePath)) {
|
|
4954
5510
|
logger.info(`Users file does not exist at ${this.filePath}, creating with empty users`);
|
|
4955
5511
|
const initialData = { users: [] };
|
|
4956
|
-
|
|
5512
|
+
import_fs4.default.writeFileSync(this.filePath, JSON.stringify(initialData, null, 4));
|
|
4957
5513
|
this.users = [];
|
|
4958
5514
|
this.hasChanged = false;
|
|
4959
5515
|
return;
|
|
4960
5516
|
}
|
|
4961
|
-
const fileContent =
|
|
5517
|
+
const fileContent = import_fs4.default.readFileSync(this.filePath, "utf-8");
|
|
4962
5518
|
const rawData = JSON.parse(fileContent);
|
|
4963
5519
|
const validatedData = UsersDataSchema.parse(rawData);
|
|
4964
5520
|
this.users = validatedData.users;
|
|
@@ -4978,15 +5534,15 @@ var UserManager = class {
|
|
|
4978
5534
|
}
|
|
4979
5535
|
try {
|
|
4980
5536
|
const dir = import_path3.default.dirname(this.filePath);
|
|
4981
|
-
if (!
|
|
4982
|
-
|
|
5537
|
+
if (!import_fs4.default.existsSync(dir)) {
|
|
5538
|
+
import_fs4.default.mkdirSync(dir, { recursive: true });
|
|
4983
5539
|
}
|
|
4984
5540
|
const usersToSave = this.users.map((user) => {
|
|
4985
5541
|
const { wsIds, ...userWithoutWsIds } = user;
|
|
4986
5542
|
return userWithoutWsIds;
|
|
4987
5543
|
});
|
|
4988
5544
|
const data = { users: usersToSave };
|
|
4989
|
-
|
|
5545
|
+
import_fs4.default.writeFileSync(this.filePath, JSON.stringify(data, null, 4));
|
|
4990
5546
|
this.hasChanged = false;
|
|
4991
5547
|
logger.debug(`Synced ${this.users.length} users to file (wsIds excluded)`);
|
|
4992
5548
|
} catch (error) {
|
|
@@ -5204,7 +5760,7 @@ var UserManager = class {
|
|
|
5204
5760
|
};
|
|
5205
5761
|
|
|
5206
5762
|
// src/dashboards/dashboard-manager.ts
|
|
5207
|
-
var
|
|
5763
|
+
var import_fs5 = __toESM(require("fs"));
|
|
5208
5764
|
var import_path4 = __toESM(require("path"));
|
|
5209
5765
|
var import_os2 = __toESM(require("os"));
|
|
5210
5766
|
var DashboardManager = class {
|
|
@@ -5239,12 +5795,12 @@ var DashboardManager = class {
|
|
|
5239
5795
|
createDashboard(dashboardId, dashboard) {
|
|
5240
5796
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5241
5797
|
const dashboardDir = import_path4.default.dirname(dashboardPath);
|
|
5242
|
-
if (
|
|
5798
|
+
if (import_fs5.default.existsSync(dashboardPath)) {
|
|
5243
5799
|
throw new Error(`Dashboard '${dashboardId}' already exists`);
|
|
5244
5800
|
}
|
|
5245
5801
|
const validated = DSLRendererPropsSchema.parse(dashboard);
|
|
5246
|
-
|
|
5247
|
-
|
|
5802
|
+
import_fs5.default.mkdirSync(dashboardDir, { recursive: true });
|
|
5803
|
+
import_fs5.default.writeFileSync(dashboardPath, JSON.stringify(validated, null, 4));
|
|
5248
5804
|
logger.info(`Dashboard created: ${dashboardId}`);
|
|
5249
5805
|
return validated;
|
|
5250
5806
|
}
|
|
@@ -5255,12 +5811,12 @@ var DashboardManager = class {
|
|
|
5255
5811
|
*/
|
|
5256
5812
|
getDashboard(dashboardId) {
|
|
5257
5813
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5258
|
-
if (!
|
|
5814
|
+
if (!import_fs5.default.existsSync(dashboardPath)) {
|
|
5259
5815
|
logger.warn(`Dashboard not found: ${dashboardId}`);
|
|
5260
5816
|
return null;
|
|
5261
5817
|
}
|
|
5262
5818
|
try {
|
|
5263
|
-
const fileContent =
|
|
5819
|
+
const fileContent = import_fs5.default.readFileSync(dashboardPath, "utf-8");
|
|
5264
5820
|
const dashboard = JSON.parse(fileContent);
|
|
5265
5821
|
const validated = DSLRendererPropsSchema.parse(dashboard);
|
|
5266
5822
|
return validated;
|
|
@@ -5274,16 +5830,16 @@ var DashboardManager = class {
|
|
|
5274
5830
|
* @returns Array of dashboard objects with their IDs
|
|
5275
5831
|
*/
|
|
5276
5832
|
getAllDashboards() {
|
|
5277
|
-
if (!
|
|
5278
|
-
|
|
5833
|
+
if (!import_fs5.default.existsSync(this.dashboardsBasePath)) {
|
|
5834
|
+
import_fs5.default.mkdirSync(this.dashboardsBasePath, { recursive: true });
|
|
5279
5835
|
return [];
|
|
5280
5836
|
}
|
|
5281
5837
|
const dashboards = [];
|
|
5282
5838
|
try {
|
|
5283
|
-
const dashboardDirs =
|
|
5839
|
+
const dashboardDirs = import_fs5.default.readdirSync(this.dashboardsBasePath);
|
|
5284
5840
|
for (const dashboardId of dashboardDirs) {
|
|
5285
5841
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5286
|
-
if (
|
|
5842
|
+
if (import_fs5.default.existsSync(dashboardPath)) {
|
|
5287
5843
|
const dashboard = this.getDashboard(dashboardId);
|
|
5288
5844
|
if (dashboard) {
|
|
5289
5845
|
dashboards.push({ dashboardId, dashboard });
|
|
@@ -5305,13 +5861,13 @@ var DashboardManager = class {
|
|
|
5305
5861
|
*/
|
|
5306
5862
|
updateDashboard(dashboardId, dashboard) {
|
|
5307
5863
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5308
|
-
if (!
|
|
5864
|
+
if (!import_fs5.default.existsSync(dashboardPath)) {
|
|
5309
5865
|
logger.warn(`Dashboard not found for update: ${dashboardId}`);
|
|
5310
5866
|
return null;
|
|
5311
5867
|
}
|
|
5312
5868
|
try {
|
|
5313
5869
|
const validated = DSLRendererPropsSchema.parse(dashboard);
|
|
5314
|
-
|
|
5870
|
+
import_fs5.default.writeFileSync(dashboardPath, JSON.stringify(validated, null, 4));
|
|
5315
5871
|
logger.info(`Dashboard updated: ${dashboardId}`);
|
|
5316
5872
|
return validated;
|
|
5317
5873
|
} catch (error) {
|
|
@@ -5327,12 +5883,12 @@ var DashboardManager = class {
|
|
|
5327
5883
|
deleteDashboard(dashboardId) {
|
|
5328
5884
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5329
5885
|
const dashboardDir = import_path4.default.dirname(dashboardPath);
|
|
5330
|
-
if (!
|
|
5886
|
+
if (!import_fs5.default.existsSync(dashboardPath)) {
|
|
5331
5887
|
logger.warn(`Dashboard not found for deletion: ${dashboardId}`);
|
|
5332
5888
|
return false;
|
|
5333
5889
|
}
|
|
5334
5890
|
try {
|
|
5335
|
-
|
|
5891
|
+
import_fs5.default.rmSync(dashboardDir, { recursive: true, force: true });
|
|
5336
5892
|
logger.info(`Dashboard deleted: ${dashboardId}`);
|
|
5337
5893
|
return true;
|
|
5338
5894
|
} catch (error) {
|
|
@@ -5347,21 +5903,21 @@ var DashboardManager = class {
|
|
|
5347
5903
|
*/
|
|
5348
5904
|
dashboardExists(dashboardId) {
|
|
5349
5905
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
5350
|
-
return
|
|
5906
|
+
return import_fs5.default.existsSync(dashboardPath);
|
|
5351
5907
|
}
|
|
5352
5908
|
/**
|
|
5353
5909
|
* Get dashboard count
|
|
5354
5910
|
* @returns Number of dashboards
|
|
5355
5911
|
*/
|
|
5356
5912
|
getDashboardCount() {
|
|
5357
|
-
if (!
|
|
5913
|
+
if (!import_fs5.default.existsSync(this.dashboardsBasePath)) {
|
|
5358
5914
|
return 0;
|
|
5359
5915
|
}
|
|
5360
5916
|
try {
|
|
5361
|
-
const dashboardDirs =
|
|
5917
|
+
const dashboardDirs = import_fs5.default.readdirSync(this.dashboardsBasePath);
|
|
5362
5918
|
return dashboardDirs.filter((dir) => {
|
|
5363
5919
|
const dashboardPath = this.getDashboardPath(dir);
|
|
5364
|
-
return
|
|
5920
|
+
return import_fs5.default.existsSync(dashboardPath);
|
|
5365
5921
|
}).length;
|
|
5366
5922
|
} catch (error) {
|
|
5367
5923
|
logger.error("Failed to get dashboard count:", error);
|
|
@@ -5371,7 +5927,7 @@ var DashboardManager = class {
|
|
|
5371
5927
|
};
|
|
5372
5928
|
|
|
5373
5929
|
// src/reports/report-manager.ts
|
|
5374
|
-
var
|
|
5930
|
+
var import_fs6 = __toESM(require("fs"));
|
|
5375
5931
|
var import_path5 = __toESM(require("path"));
|
|
5376
5932
|
var import_os3 = __toESM(require("os"));
|
|
5377
5933
|
var ReportManager = class {
|
|
@@ -5406,12 +5962,12 @@ var ReportManager = class {
|
|
|
5406
5962
|
createReport(reportId, report) {
|
|
5407
5963
|
const reportPath = this.getReportPath(reportId);
|
|
5408
5964
|
const reportDir = import_path5.default.dirname(reportPath);
|
|
5409
|
-
if (
|
|
5965
|
+
if (import_fs6.default.existsSync(reportPath)) {
|
|
5410
5966
|
throw new Error(`Report '${reportId}' already exists`);
|
|
5411
5967
|
}
|
|
5412
5968
|
const validated = DSLRendererPropsSchema2.parse(report);
|
|
5413
|
-
|
|
5414
|
-
|
|
5969
|
+
import_fs6.default.mkdirSync(reportDir, { recursive: true });
|
|
5970
|
+
import_fs6.default.writeFileSync(reportPath, JSON.stringify(validated, null, 4));
|
|
5415
5971
|
logger.info(`Report created: ${reportId}`);
|
|
5416
5972
|
return validated;
|
|
5417
5973
|
}
|
|
@@ -5422,12 +5978,12 @@ var ReportManager = class {
|
|
|
5422
5978
|
*/
|
|
5423
5979
|
getReport(reportId) {
|
|
5424
5980
|
const reportPath = this.getReportPath(reportId);
|
|
5425
|
-
if (!
|
|
5981
|
+
if (!import_fs6.default.existsSync(reportPath)) {
|
|
5426
5982
|
logger.warn(`Report not found: ${reportId}`);
|
|
5427
5983
|
return null;
|
|
5428
5984
|
}
|
|
5429
5985
|
try {
|
|
5430
|
-
const fileContent =
|
|
5986
|
+
const fileContent = import_fs6.default.readFileSync(reportPath, "utf-8");
|
|
5431
5987
|
const report = JSON.parse(fileContent);
|
|
5432
5988
|
const validated = DSLRendererPropsSchema2.parse(report);
|
|
5433
5989
|
return validated;
|
|
@@ -5441,16 +5997,16 @@ var ReportManager = class {
|
|
|
5441
5997
|
* @returns Array of report objects with their IDs
|
|
5442
5998
|
*/
|
|
5443
5999
|
getAllReports() {
|
|
5444
|
-
if (!
|
|
5445
|
-
|
|
6000
|
+
if (!import_fs6.default.existsSync(this.reportsBasePath)) {
|
|
6001
|
+
import_fs6.default.mkdirSync(this.reportsBasePath, { recursive: true });
|
|
5446
6002
|
return [];
|
|
5447
6003
|
}
|
|
5448
6004
|
const reports = [];
|
|
5449
6005
|
try {
|
|
5450
|
-
const reportDirs =
|
|
6006
|
+
const reportDirs = import_fs6.default.readdirSync(this.reportsBasePath);
|
|
5451
6007
|
for (const reportId of reportDirs) {
|
|
5452
6008
|
const reportPath = this.getReportPath(reportId);
|
|
5453
|
-
if (
|
|
6009
|
+
if (import_fs6.default.existsSync(reportPath)) {
|
|
5454
6010
|
const report = this.getReport(reportId);
|
|
5455
6011
|
if (report) {
|
|
5456
6012
|
reports.push({ reportId, report });
|
|
@@ -5472,13 +6028,13 @@ var ReportManager = class {
|
|
|
5472
6028
|
*/
|
|
5473
6029
|
updateReport(reportId, report) {
|
|
5474
6030
|
const reportPath = this.getReportPath(reportId);
|
|
5475
|
-
if (!
|
|
6031
|
+
if (!import_fs6.default.existsSync(reportPath)) {
|
|
5476
6032
|
logger.warn(`Report not found for update: ${reportId}`);
|
|
5477
6033
|
return null;
|
|
5478
6034
|
}
|
|
5479
6035
|
try {
|
|
5480
6036
|
const validated = DSLRendererPropsSchema2.parse(report);
|
|
5481
|
-
|
|
6037
|
+
import_fs6.default.writeFileSync(reportPath, JSON.stringify(validated, null, 4));
|
|
5482
6038
|
logger.info(`Report updated: ${reportId}`);
|
|
5483
6039
|
return validated;
|
|
5484
6040
|
} catch (error) {
|
|
@@ -5494,12 +6050,12 @@ var ReportManager = class {
|
|
|
5494
6050
|
deleteReport(reportId) {
|
|
5495
6051
|
const reportPath = this.getReportPath(reportId);
|
|
5496
6052
|
const reportDir = import_path5.default.dirname(reportPath);
|
|
5497
|
-
if (!
|
|
6053
|
+
if (!import_fs6.default.existsSync(reportPath)) {
|
|
5498
6054
|
logger.warn(`Report not found for deletion: ${reportId}`);
|
|
5499
6055
|
return false;
|
|
5500
6056
|
}
|
|
5501
6057
|
try {
|
|
5502
|
-
|
|
6058
|
+
import_fs6.default.rmSync(reportDir, { recursive: true, force: true });
|
|
5503
6059
|
logger.info(`Report deleted: ${reportId}`);
|
|
5504
6060
|
return true;
|
|
5505
6061
|
} catch (error) {
|
|
@@ -5514,21 +6070,21 @@ var ReportManager = class {
|
|
|
5514
6070
|
*/
|
|
5515
6071
|
reportExists(reportId) {
|
|
5516
6072
|
const reportPath = this.getReportPath(reportId);
|
|
5517
|
-
return
|
|
6073
|
+
return import_fs6.default.existsSync(reportPath);
|
|
5518
6074
|
}
|
|
5519
6075
|
/**
|
|
5520
6076
|
* Get report count
|
|
5521
6077
|
* @returns Number of reports
|
|
5522
6078
|
*/
|
|
5523
6079
|
getReportCount() {
|
|
5524
|
-
if (!
|
|
6080
|
+
if (!import_fs6.default.existsSync(this.reportsBasePath)) {
|
|
5525
6081
|
return 0;
|
|
5526
6082
|
}
|
|
5527
6083
|
try {
|
|
5528
|
-
const reportDirs =
|
|
6084
|
+
const reportDirs = import_fs6.default.readdirSync(this.reportsBasePath);
|
|
5529
6085
|
return reportDirs.filter((dir) => {
|
|
5530
6086
|
const reportPath = this.getReportPath(dir);
|
|
5531
|
-
return
|
|
6087
|
+
return import_fs6.default.existsSync(reportPath);
|
|
5532
6088
|
}).length;
|
|
5533
6089
|
} catch (error) {
|
|
5534
6090
|
logger.error("Failed to get report count:", error);
|
|
@@ -5752,9 +6308,6 @@ var SuperatomSDK = class {
|
|
|
5752
6308
|
});
|
|
5753
6309
|
this.initializeDashboardManager();
|
|
5754
6310
|
this.initializeReportManager();
|
|
5755
|
-
this.connect().catch((error) => {
|
|
5756
|
-
logger.error("Failed to connect to Superatom:", error);
|
|
5757
|
-
});
|
|
5758
6311
|
}
|
|
5759
6312
|
/**
|
|
5760
6313
|
* Initialize PromptLoader and load prompts into memory
|
|
@@ -5820,6 +6373,10 @@ var SuperatomSDK = class {
|
|
|
5820
6373
|
* Connect to the Superatom WebSocket service
|
|
5821
6374
|
*/
|
|
5822
6375
|
async connect() {
|
|
6376
|
+
if (this.connected && this.ws && this.ws.readyState === this.ws.OPEN) {
|
|
6377
|
+
logger.info("Already connected to WebSocket");
|
|
6378
|
+
return Promise.resolve();
|
|
6379
|
+
}
|
|
5823
6380
|
return new Promise((resolve, reject) => {
|
|
5824
6381
|
try {
|
|
5825
6382
|
const url = new URL(this.url);
|
|
@@ -5882,7 +6439,7 @@ var SuperatomSDK = class {
|
|
|
5882
6439
|
});
|
|
5883
6440
|
break;
|
|
5884
6441
|
case "USER_PROMPT_REQ":
|
|
5885
|
-
handleUserPromptRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.llmProviders).catch((error) => {
|
|
6442
|
+
handleUserPromptRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.llmProviders, this.collections).catch((error) => {
|
|
5886
6443
|
logger.error("Failed to handle user prompt request:", error);
|
|
5887
6444
|
});
|
|
5888
6445
|
break;
|