@superatomai/sdk-node 0.0.8 → 0.0.10

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/dist/index.mjs CHANGED
@@ -1,439 +1,12 @@
1
- var __create = Object.create;
2
1
  var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
2
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
- }) : x)(function(x) {
10
- if (typeof require !== "undefined") return require.apply(this, arguments);
11
- throw Error('Dynamic require of "' + x + '" is not supported');
12
- });
13
3
  var __esm = (fn, res) => function __init() {
14
4
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
15
5
  };
16
- var __commonJS = (cb, mod) => function __require2() {
17
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
18
- };
19
6
  var __export = (target, all) => {
20
7
  for (var name in all)
21
8
  __defProp(target, name, { get: all[name], enumerable: true });
22
9
  };
23
- var __copyProps = (to, from, except, desc) => {
24
- if (from && typeof from === "object" || typeof from === "function") {
25
- for (let key of __getOwnPropNames(from))
26
- if (!__hasOwnProp.call(to, key) && key !== except)
27
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
28
- }
29
- return to;
30
- };
31
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
32
- // If the importer is in node compatibility mode or this is not an ESM
33
- // file that has been converted to a CommonJS file using a Babel-
34
- // compatible transform (i.e. "__esModule" has not been set), then set
35
- // "default" to the CommonJS "module.exports" for node compatibility.
36
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
37
- mod
38
- ));
39
-
40
- // node_modules/dotenv/package.json
41
- var require_package = __commonJS({
42
- "node_modules/dotenv/package.json"(exports, module) {
43
- module.exports = {
44
- name: "dotenv",
45
- version: "17.2.3",
46
- description: "Loads environment variables from .env file",
47
- main: "lib/main.js",
48
- types: "lib/main.d.ts",
49
- exports: {
50
- ".": {
51
- types: "./lib/main.d.ts",
52
- require: "./lib/main.js",
53
- default: "./lib/main.js"
54
- },
55
- "./config": "./config.js",
56
- "./config.js": "./config.js",
57
- "./lib/env-options": "./lib/env-options.js",
58
- "./lib/env-options.js": "./lib/env-options.js",
59
- "./lib/cli-options": "./lib/cli-options.js",
60
- "./lib/cli-options.js": "./lib/cli-options.js",
61
- "./package.json": "./package.json"
62
- },
63
- scripts: {
64
- "dts-check": "tsc --project tests/types/tsconfig.json",
65
- lint: "standard",
66
- pretest: "npm run lint && npm run dts-check",
67
- test: "tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000",
68
- "test:coverage": "tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
69
- prerelease: "npm test",
70
- release: "standard-version"
71
- },
72
- repository: {
73
- type: "git",
74
- url: "git://github.com/motdotla/dotenv.git"
75
- },
76
- homepage: "https://github.com/motdotla/dotenv#readme",
77
- funding: "https://dotenvx.com",
78
- keywords: [
79
- "dotenv",
80
- "env",
81
- ".env",
82
- "environment",
83
- "variables",
84
- "config",
85
- "settings"
86
- ],
87
- readmeFilename: "README.md",
88
- license: "BSD-2-Clause",
89
- devDependencies: {
90
- "@types/node": "^18.11.3",
91
- decache: "^4.6.2",
92
- sinon: "^14.0.1",
93
- standard: "^17.0.0",
94
- "standard-version": "^9.5.0",
95
- tap: "^19.2.0",
96
- typescript: "^4.8.4"
97
- },
98
- engines: {
99
- node: ">=12"
100
- },
101
- browser: {
102
- fs: false
103
- }
104
- };
105
- }
106
- });
107
-
108
- // node_modules/dotenv/lib/main.js
109
- var require_main = __commonJS({
110
- "node_modules/dotenv/lib/main.js"(exports, module) {
111
- "use strict";
112
- var fs8 = __require("fs");
113
- var path7 = __require("path");
114
- var os4 = __require("os");
115
- var crypto2 = __require("crypto");
116
- var packageJson = require_package();
117
- var version = packageJson.version;
118
- var TIPS = [
119
- "\u{1F510} encrypt with Dotenvx: https://dotenvx.com",
120
- "\u{1F510} prevent committing .env to code: https://dotenvx.com/precommit",
121
- "\u{1F510} prevent building .env in docker: https://dotenvx.com/prebuild",
122
- "\u{1F4E1} add observability to secrets: https://dotenvx.com/ops",
123
- "\u{1F465} sync secrets across teammates & machines: https://dotenvx.com/ops",
124
- "\u{1F5C2}\uFE0F backup and recover secrets: https://dotenvx.com/ops",
125
- "\u2705 audit secrets and track compliance: https://dotenvx.com/ops",
126
- "\u{1F504} add secrets lifecycle management: https://dotenvx.com/ops",
127
- "\u{1F511} add access controls to secrets: https://dotenvx.com/ops",
128
- "\u{1F6E0}\uFE0F run anywhere with `dotenvx run -- yourcommand`",
129
- "\u2699\uFE0F specify custom .env file path with { path: '/custom/path/.env' }",
130
- "\u2699\uFE0F enable debug logging with { debug: true }",
131
- "\u2699\uFE0F override existing env vars with { override: true }",
132
- "\u2699\uFE0F suppress all logs with { quiet: true }",
133
- "\u2699\uFE0F write to custom object with { processEnv: myObject }",
134
- "\u2699\uFE0F load multiple .env files with { path: ['.env.local', '.env'] }"
135
- ];
136
- function _getRandomTip() {
137
- return TIPS[Math.floor(Math.random() * TIPS.length)];
138
- }
139
- function parseBoolean(value) {
140
- if (typeof value === "string") {
141
- return !["false", "0", "no", "off", ""].includes(value.toLowerCase());
142
- }
143
- return Boolean(value);
144
- }
145
- function supportsAnsi() {
146
- return process.stdout.isTTY;
147
- }
148
- function dim(text) {
149
- return supportsAnsi() ? `\x1B[2m${text}\x1B[0m` : text;
150
- }
151
- var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
152
- function parse(src) {
153
- const obj = {};
154
- let lines = src.toString();
155
- lines = lines.replace(/\r\n?/mg, "\n");
156
- let match;
157
- while ((match = LINE.exec(lines)) != null) {
158
- const key = match[1];
159
- let value = match[2] || "";
160
- value = value.trim();
161
- const maybeQuote = value[0];
162
- value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
163
- if (maybeQuote === '"') {
164
- value = value.replace(/\\n/g, "\n");
165
- value = value.replace(/\\r/g, "\r");
166
- }
167
- obj[key] = value;
168
- }
169
- return obj;
170
- }
171
- function _parseVault(options) {
172
- options = options || {};
173
- const vaultPath = _vaultPath(options);
174
- options.path = vaultPath;
175
- const result = DotenvModule.configDotenv(options);
176
- if (!result.parsed) {
177
- const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
178
- err.code = "MISSING_DATA";
179
- throw err;
180
- }
181
- const keys = _dotenvKey(options).split(",");
182
- const length = keys.length;
183
- let decrypted;
184
- for (let i = 0; i < length; i++) {
185
- try {
186
- const key = keys[i].trim();
187
- const attrs = _instructions(result, key);
188
- decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
189
- break;
190
- } catch (error) {
191
- if (i + 1 >= length) {
192
- throw error;
193
- }
194
- }
195
- }
196
- return DotenvModule.parse(decrypted);
197
- }
198
- function _warn(message) {
199
- console.error(`[dotenv@${version}][WARN] ${message}`);
200
- }
201
- function _debug(message) {
202
- console.log(`[dotenv@${version}][DEBUG] ${message}`);
203
- }
204
- function _log(message) {
205
- console.log(`[dotenv@${version}] ${message}`);
206
- }
207
- function _dotenvKey(options) {
208
- if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
209
- return options.DOTENV_KEY;
210
- }
211
- if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
212
- return process.env.DOTENV_KEY;
213
- }
214
- return "";
215
- }
216
- function _instructions(result, dotenvKey) {
217
- let uri;
218
- try {
219
- uri = new URL(dotenvKey);
220
- } catch (error) {
221
- if (error.code === "ERR_INVALID_URL") {
222
- const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
223
- err.code = "INVALID_DOTENV_KEY";
224
- throw err;
225
- }
226
- throw error;
227
- }
228
- const key = uri.password;
229
- if (!key) {
230
- const err = new Error("INVALID_DOTENV_KEY: Missing key part");
231
- err.code = "INVALID_DOTENV_KEY";
232
- throw err;
233
- }
234
- const environment = uri.searchParams.get("environment");
235
- if (!environment) {
236
- const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
237
- err.code = "INVALID_DOTENV_KEY";
238
- throw err;
239
- }
240
- const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
241
- const ciphertext = result.parsed[environmentKey];
242
- if (!ciphertext) {
243
- const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
244
- err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
245
- throw err;
246
- }
247
- return { ciphertext, key };
248
- }
249
- function _vaultPath(options) {
250
- let possibleVaultPath = null;
251
- if (options && options.path && options.path.length > 0) {
252
- if (Array.isArray(options.path)) {
253
- for (const filepath of options.path) {
254
- if (fs8.existsSync(filepath)) {
255
- possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
256
- }
257
- }
258
- } else {
259
- possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
260
- }
261
- } else {
262
- possibleVaultPath = path7.resolve(process.cwd(), ".env.vault");
263
- }
264
- if (fs8.existsSync(possibleVaultPath)) {
265
- return possibleVaultPath;
266
- }
267
- return null;
268
- }
269
- function _resolveHome(envPath) {
270
- return envPath[0] === "~" ? path7.join(os4.homedir(), envPath.slice(1)) : envPath;
271
- }
272
- function _configVault(options) {
273
- const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
274
- const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options && options.quiet);
275
- if (debug || !quiet) {
276
- _log("Loading env from encrypted .env.vault");
277
- }
278
- const parsed = DotenvModule._parseVault(options);
279
- let processEnv = process.env;
280
- if (options && options.processEnv != null) {
281
- processEnv = options.processEnv;
282
- }
283
- DotenvModule.populate(processEnv, parsed, options);
284
- return { parsed };
285
- }
286
- function configDotenv(options) {
287
- const dotenvPath = path7.resolve(process.cwd(), ".env");
288
- let encoding = "utf8";
289
- let processEnv = process.env;
290
- if (options && options.processEnv != null) {
291
- processEnv = options.processEnv;
292
- }
293
- let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options && options.debug);
294
- let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options && options.quiet);
295
- if (options && options.encoding) {
296
- encoding = options.encoding;
297
- } else {
298
- if (debug) {
299
- _debug("No encoding is specified. UTF-8 is used by default");
300
- }
301
- }
302
- let optionPaths = [dotenvPath];
303
- if (options && options.path) {
304
- if (!Array.isArray(options.path)) {
305
- optionPaths = [_resolveHome(options.path)];
306
- } else {
307
- optionPaths = [];
308
- for (const filepath of options.path) {
309
- optionPaths.push(_resolveHome(filepath));
310
- }
311
- }
312
- }
313
- let lastError;
314
- const parsedAll = {};
315
- for (const path8 of optionPaths) {
316
- try {
317
- const parsed = DotenvModule.parse(fs8.readFileSync(path8, { encoding }));
318
- DotenvModule.populate(parsedAll, parsed, options);
319
- } catch (e) {
320
- if (debug) {
321
- _debug(`Failed to load ${path8} ${e.message}`);
322
- }
323
- lastError = e;
324
- }
325
- }
326
- const populated = DotenvModule.populate(processEnv, parsedAll, options);
327
- debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug);
328
- quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
329
- if (debug || !quiet) {
330
- const keysCount = Object.keys(populated).length;
331
- const shortPaths = [];
332
- for (const filePath of optionPaths) {
333
- try {
334
- const relative = path7.relative(process.cwd(), filePath);
335
- shortPaths.push(relative);
336
- } catch (e) {
337
- if (debug) {
338
- _debug(`Failed to load ${filePath} ${e.message}`);
339
- }
340
- lastError = e;
341
- }
342
- }
343
- _log(`injecting env (${keysCount}) from ${shortPaths.join(",")} ${dim(`-- tip: ${_getRandomTip()}`)}`);
344
- }
345
- if (lastError) {
346
- return { parsed: parsedAll, error: lastError };
347
- } else {
348
- return { parsed: parsedAll };
349
- }
350
- }
351
- function config(options) {
352
- if (_dotenvKey(options).length === 0) {
353
- return DotenvModule.configDotenv(options);
354
- }
355
- const vaultPath = _vaultPath(options);
356
- if (!vaultPath) {
357
- _warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
358
- return DotenvModule.configDotenv(options);
359
- }
360
- return DotenvModule._configVault(options);
361
- }
362
- function decrypt(encrypted, keyStr) {
363
- const key = Buffer.from(keyStr.slice(-64), "hex");
364
- let ciphertext = Buffer.from(encrypted, "base64");
365
- const nonce = ciphertext.subarray(0, 12);
366
- const authTag = ciphertext.subarray(-16);
367
- ciphertext = ciphertext.subarray(12, -16);
368
- try {
369
- const aesgcm = crypto2.createDecipheriv("aes-256-gcm", key, nonce);
370
- aesgcm.setAuthTag(authTag);
371
- return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
372
- } catch (error) {
373
- const isRange = error instanceof RangeError;
374
- const invalidKeyLength = error.message === "Invalid key length";
375
- const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
376
- if (isRange || invalidKeyLength) {
377
- const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
378
- err.code = "INVALID_DOTENV_KEY";
379
- throw err;
380
- } else if (decryptionFailed) {
381
- const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
382
- err.code = "DECRYPTION_FAILED";
383
- throw err;
384
- } else {
385
- throw error;
386
- }
387
- }
388
- }
389
- function populate(processEnv, parsed, options = {}) {
390
- const debug = Boolean(options && options.debug);
391
- const override = Boolean(options && options.override);
392
- const populated = {};
393
- if (typeof parsed !== "object") {
394
- const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
395
- err.code = "OBJECT_REQUIRED";
396
- throw err;
397
- }
398
- for (const key of Object.keys(parsed)) {
399
- if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
400
- if (override === true) {
401
- processEnv[key] = parsed[key];
402
- populated[key] = parsed[key];
403
- }
404
- if (debug) {
405
- if (override === true) {
406
- _debug(`"${key}" is already defined and WAS overwritten`);
407
- } else {
408
- _debug(`"${key}" is already defined and was NOT overwritten`);
409
- }
410
- }
411
- } else {
412
- processEnv[key] = parsed[key];
413
- populated[key] = parsed[key];
414
- }
415
- }
416
- return populated;
417
- }
418
- var DotenvModule = {
419
- configDotenv,
420
- _configVault,
421
- _parseVault,
422
- config,
423
- decrypt,
424
- parse,
425
- populate
426
- };
427
- module.exports.configDotenv = DotenvModule.configDotenv;
428
- module.exports._configVault = DotenvModule._configVault;
429
- module.exports._parseVault = DotenvModule._parseVault;
430
- module.exports.config = DotenvModule.config;
431
- module.exports.decrypt = DotenvModule.decrypt;
432
- module.exports.parse = DotenvModule.parse;
433
- module.exports.populate = DotenvModule.populate;
434
- module.exports = DotenvModule;
435
- }
436
- });
437
10
 
438
11
  // src/userResponse/utils.ts
439
12
  var utils_exports = {};
@@ -847,7 +420,7 @@ var UserPromptSuggestionsMessageSchema = z3.object({
847
420
  payload: UserPromptSuggestionsPayloadSchema
848
421
  });
849
422
  var ComponentPropsSchema = z3.object({
850
- query: z3.string().optional(),
423
+ query: z3.string().or(z3.object({})).optional(),
851
424
  title: z3.string().optional(),
852
425
  description: z3.string().optional(),
853
426
  config: z3.record(z3.unknown()).optional(),
@@ -2046,7 +1619,7 @@ function sendDataResponse3(id, res, sendMessage, clientId) {
2046
1619
  }
2047
1620
 
2048
1621
  // src/userResponse/groq.ts
2049
- var import_dotenv = __toESM(require_main());
1622
+ import dotenv from "dotenv";
2050
1623
 
2051
1624
  // src/userResponse/base-llm.ts
2052
1625
  init_utils();
@@ -2674,6 +2247,7 @@ When the user asks about data
2674
2247
 
2675
2248
  After analyzing the query results, you MUST suggest appropriate dashboard components for displaying the data. Use this format:
2676
2249
 
2250
+ <DashboardComponents>
2677
2251
  **Dashboard Components:**
2678
2252
  Format: \`{number}.{component_type} : {clear reasoning}\`
2679
2253
 
@@ -2682,9 +2256,9 @@ Format: \`{number}.{component_type} : {clear reasoning}\`
2682
2256
  1. Analyze the query results structure and data type
2683
2257
  2. Suggest components that would best visualize the data
2684
2258
  3. Each component suggestion must be on a new line
2259
+ </DashboardComponents>
2685
2260
 
2686
-
2687
- IMPORTANT: Always include the **Dashboard Components:** section with at least one component suggestion when data is returned.
2261
+ IMPORTANT: Always wrap component suggestions with <DashboardComponents> tags and include at least one component suggestion when data is returned.
2688
2262
 
2689
2263
  ## Output Format
2690
2264
 
@@ -2692,7 +2266,7 @@ Respond with plain text that includes:
2692
2266
 
2693
2267
  1. **Query Analysis** (if applicable): Brief explanation of what data was fetched
2694
2268
  2. **Results Summary**: Present the data in a clear, readable format
2695
- 3. **Dashboard Components**: List suggested components in the c1:type format
2269
+ 3. **Dashboard Components**: List suggested components wrapped in <DashboardComponents> tags
2696
2270
 
2697
2271
 
2698
2272
  **CRITICAL:**
@@ -2769,39 +2343,22 @@ You will receive a text response containing:
2769
2343
  3. **Dashboard Components:** suggestions (1:component_type : reasoning format)
2770
2344
 
2771
2345
  Your job is to:
2772
- 1. **DISCOVER and SELECT the best dashboard layout component** from the available components list
2773
- 2. Parse the component suggestions from the text response
2774
- 3. Match each suggestion with an actual component from the available list
2775
- 4. Generate the RIGHT NUMBER of components to fit the selected layout perfectly (based on the layout component's description)
2776
- 5. Generate proper props to **visualize the analysis results** that were already fetched
2777
- 6. **Generate intelligent follow-up questions (actions)** that the user might naturally ask next based on the data analysis
2346
+ 1. **Parse the component suggestions** from the text response (format: 1:component_type : reasoning)
2347
+ 2. **Match each suggestion with an actual component** from the available list
2348
+ 3. **Generate proper props** for each matched component to **visualize the analysis results** that were already fetched
2349
+ 4. **SELECT the best dashboard layout component** that can accommodate all the matched components
2350
+ 5. **Generate intelligent follow-up questions (actions)** that the user might naturally ask next based on the data analysis
2778
2351
 
2779
2352
  **CRITICAL GOAL**: Create dashboard components that display the **same data that was already analyzed** - NOT new data. The queries already ran and got results. You're just creating different visualizations of those results.
2780
2353
 
2781
-
2782
-
2783
- ## Layout Component Discovery
2784
- **Find layout components** by looking for components with \`type: "DashboardLayout"\`
2785
-
2786
- ## Layout Selection Logic
2787
- 1. **Read each layout's description** to understand:
2788
- - What structure it provides
2789
- - When it's best used (e.g., comprehensive analysis vs focused analysis)
2790
- - The exact number and types of components it requires
2791
- 2. **Select the best layout** based on:
2792
- - Which layout structure best fits the analysis needs
2793
- - The component suggestions from the text response
2794
- - The user question and data complexity
2795
- 3. **Generate EXACTLY the components specified** in the selected layout's description
2796
-
2797
- **IMPORTANT:** Always prefer structured dashboard layouts when available. The layout component's description will tell you exactly what components to generate.
2354
+ **APPROACH**: First match all the components suggested in the text response, THEN find the layout that best fits those components.
2798
2355
 
2799
2356
  ## Available Components
2800
2357
 
2801
2358
  {{AVAILABLE_COMPONENTS}}
2802
2359
 
2803
- ## Component Matching Rules
2804
- For each component suggestion (c1, c2, c3, etc.):
2360
+ ## Component Matching Rules (STEP 1)
2361
+ For each component suggestion (c1, c2, c3, etc.) from the text response:
2805
2362
 
2806
2363
  1. **Match by type**: Find components whose \`type\` matches the suggested component type
2807
2364
  2. **Refine by relevance**: If multiple components match, choose based on:
@@ -2809,6 +2366,24 @@ For each component suggestion (c1, c2, c3, etc.):
2809
2366
  - Best fit for the data being visualized
2810
2367
  3. **Fallback**: If no exact type match, find the closest alternative
2811
2368
 
2369
+ ## Layout Selection Logic (STEP 2 - After Matching Components)
2370
+
2371
+ **After you have matched all components**, select the best dashboard layout:
2372
+
2373
+ 1. **Find layout components** by looking for components with \`type: "DashboardLayout"\` in the available components list
2374
+ 2. **Read each layout's description** to understand:
2375
+ - What structure it provides
2376
+ - When it's best used (e.g., comprehensive analysis vs focused analysis)
2377
+ - The number and types of components it can accommodate
2378
+ 3. **Select the best layout** based on:
2379
+ - Which layout can best display ALL the matched components
2380
+ - The layout's capacity (how many components it supports)
2381
+ - The types of matched components (KPI, charts, tables, etc.)
2382
+ - The user question and data complexity
2383
+ 4. **If no specific layout fits**, fall back to "MultiComponentContainer" as the default layout
2384
+
2385
+ **IMPORTANT:** The layout should be chosen to FIT the matched components, not the other way around. Don't force components to fit a layout - find a layout that accommodates your components.
2386
+
2812
2387
  ## Props Generation Rules
2813
2388
 
2814
2389
  For each matched component, generate complete props:
@@ -2921,7 +2496,6 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
2921
2496
 
2922
2497
  \`\`\`json
2923
2498
  {
2924
- "selectedLayout": "Name of the selected layout component from available components",
2925
2499
  "selectedLayoutId": "id_of_the_selected_layout_component",
2926
2500
  "layoutReasoning": "Why this layout was selected based on its description and the analysis needs",
2927
2501
  "matchedComponents": [
@@ -2953,13 +2527,14 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
2953
2527
  \`\`\`
2954
2528
 
2955
2529
  **CRITICAL:**
2956
- - \`selectedLayout\` MUST be the NAME of a layout component from the available components list (must have type "DashboardLayout")
2957
- - \`selectedLayoutId\` MUST be the ID of the selected layout component
2530
+ - \`matchedComponents\` MUST include ALL components suggested in the text response (match them first!)
2531
+ - \`selectedLayoutId\` MUST be the ID of the selected layout component (must have type "DashboardLayout")
2958
2532
  - \`layoutReasoning\` MUST explain:
2959
2533
  - Why you chose this specific layout component
2960
- - How its structure (from its description) matches the analysis needs
2961
- - What components it requires based on its description
2962
- - \`matchedComponents\` array length and types MUST match what the selected layout's description specifies
2534
+ - How many components you matched (e.g., "Matched 3 components: 1 KPI, 1 chart, 1 table")
2535
+ - Why this layout is the best fit for displaying these specific matched components
2536
+ - What makes this layout appropriate for the component types and count
2537
+ - The layout selection happens AFTER component matching - don't force components to fit a pre-selected layout
2963
2538
  - \`actions\` MUST be an array of 4-5 intelligent follow-up questions based on the analysis
2964
2539
  - Return ONLY valid JSON (no markdown code blocks, no text before/after)
2965
2540
  - Generate complete props for each component
@@ -3155,6 +2730,7 @@ var promptLoader = new PromptLoader({
3155
2730
  // src/llm.ts
3156
2731
  import Anthropic from "@anthropic-ai/sdk";
3157
2732
  import Groq from "groq-sdk";
2733
+ import { jsonrepair } from "jsonrepair";
3158
2734
  var LLM = class {
3159
2735
  /* Get a complete text response from an LLM (Anthropic or Groq) */
3160
2736
  static async text(messages, options = {}) {
@@ -3276,65 +2852,110 @@ var LLM = class {
3276
2852
  let finalText = "";
3277
2853
  while (iterations < maxIterations) {
3278
2854
  iterations++;
3279
- const response = await client.messages.create({
2855
+ const stream = await client.messages.create({
3280
2856
  model: modelName,
3281
2857
  max_tokens: options.maxTokens || 4e3,
3282
2858
  temperature: options.temperature,
3283
2859
  system: messages.sys,
3284
2860
  messages: conversationMessages,
3285
- tools
2861
+ tools,
2862
+ stream: true
2863
+ // Enable streaming
3286
2864
  });
3287
- if (response.stop_reason === "end_turn") {
3288
- const textBlock = response.content.find((block) => block.type === "text");
3289
- if (textBlock && textBlock.type === "text") {
3290
- finalText = textBlock.text;
3291
- if (options.partial) {
3292
- options.partial(finalText);
2865
+ let stopReason = null;
2866
+ const contentBlocks = [];
2867
+ let currentTextBlock = "";
2868
+ let currentToolUse = null;
2869
+ for await (const chunk of stream) {
2870
+ if (chunk.type === "message_start") {
2871
+ contentBlocks.length = 0;
2872
+ currentTextBlock = "";
2873
+ currentToolUse = null;
2874
+ }
2875
+ if (chunk.type === "content_block_start") {
2876
+ if (chunk.content_block.type === "text") {
2877
+ currentTextBlock = "";
2878
+ } else if (chunk.content_block.type === "tool_use") {
2879
+ currentToolUse = {
2880
+ type: "tool_use",
2881
+ id: chunk.content_block.id,
2882
+ name: chunk.content_block.name,
2883
+ input: {}
2884
+ };
2885
+ }
2886
+ }
2887
+ if (chunk.type === "content_block_delta") {
2888
+ if (chunk.delta.type === "text_delta") {
2889
+ const text = chunk.delta.text;
2890
+ currentTextBlock += text;
2891
+ if (options.partial) {
2892
+ options.partial(text);
2893
+ }
2894
+ } else if (chunk.delta.type === "input_json_delta" && currentToolUse) {
2895
+ currentToolUse.inputJson = (currentToolUse.inputJson || "") + chunk.delta.partial_json;
2896
+ }
2897
+ }
2898
+ if (chunk.type === "content_block_stop") {
2899
+ if (currentTextBlock) {
2900
+ contentBlocks.push({
2901
+ type: "text",
2902
+ text: currentTextBlock
2903
+ });
2904
+ finalText = currentTextBlock;
2905
+ currentTextBlock = "";
2906
+ } else if (currentToolUse) {
2907
+ try {
2908
+ currentToolUse.input = currentToolUse.inputJson ? JSON.parse(currentToolUse.inputJson) : {};
2909
+ } catch (error) {
2910
+ currentToolUse.input = {};
2911
+ }
2912
+ delete currentToolUse.inputJson;
2913
+ contentBlocks.push(currentToolUse);
2914
+ currentToolUse = null;
3293
2915
  }
3294
2916
  }
2917
+ if (chunk.type === "message_delta") {
2918
+ stopReason = chunk.delta.stop_reason || stopReason;
2919
+ }
2920
+ if (chunk.type === "message_stop") {
2921
+ break;
2922
+ }
2923
+ }
2924
+ if (stopReason === "end_turn") {
3295
2925
  break;
3296
2926
  }
3297
- if (response.stop_reason === "tool_use") {
3298
- const toolUses = response.content.filter((block) => block.type === "tool_use");
2927
+ if (stopReason === "tool_use") {
2928
+ const toolUses = contentBlocks.filter((block) => block.type === "tool_use");
3299
2929
  if (toolUses.length === 0) {
3300
2930
  break;
3301
2931
  }
3302
2932
  conversationMessages.push({
3303
2933
  role: "assistant",
3304
- content: response.content
2934
+ content: contentBlocks
3305
2935
  });
3306
2936
  const toolResults = {
3307
2937
  role: "user",
3308
2938
  content: []
3309
2939
  };
3310
2940
  for (const toolUse of toolUses) {
3311
- if (toolUse.type === "tool_use") {
3312
- try {
3313
- const result = await toolHandler(toolUse.name, toolUse.input);
3314
- toolResults.content.push({
3315
- type: "tool_result",
3316
- tool_use_id: toolUse.id,
3317
- content: typeof result === "string" ? result : JSON.stringify(result)
3318
- });
3319
- } catch (error) {
3320
- toolResults.content.push({
3321
- type: "tool_result",
3322
- tool_use_id: toolUse.id,
3323
- content: error instanceof Error ? error.message : String(error),
3324
- is_error: true
3325
- });
3326
- }
2941
+ try {
2942
+ const result = await toolHandler(toolUse.name, toolUse.input);
2943
+ toolResults.content.push({
2944
+ type: "tool_result",
2945
+ tool_use_id: toolUse.id,
2946
+ content: typeof result === "string" ? result : JSON.stringify(result)
2947
+ });
2948
+ } catch (error) {
2949
+ toolResults.content.push({
2950
+ type: "tool_result",
2951
+ tool_use_id: toolUse.id,
2952
+ content: error instanceof Error ? error.message : String(error),
2953
+ is_error: true
2954
+ });
3327
2955
  }
3328
2956
  }
3329
2957
  conversationMessages.push(toolResults);
3330
2958
  } else {
3331
- const textBlock = response.content.find((block) => block.type === "text");
3332
- if (textBlock && textBlock.type === "text") {
3333
- finalText = textBlock.text;
3334
- if (options.partial) {
3335
- options.partial(finalText);
3336
- }
3337
- }
3338
2959
  break;
3339
2960
  }
3340
2961
  }
@@ -3397,9 +3018,9 @@ var LLM = class {
3397
3018
  // ============================================================
3398
3019
  /**
3399
3020
  * Parse JSON string, handling markdown code blocks and surrounding text
3400
- * Enhanced version from anthropic.ts implementation
3021
+ * Enhanced version with jsonrepair to handle malformed JSON from LLMs
3401
3022
  * @param text - Text that may contain JSON wrapped in ```json...``` or with surrounding text
3402
- * @returns Parsed JSON object
3023
+ * @returns Parsed JSON object or array
3403
3024
  */
3404
3025
  static _parseJSON(text) {
3405
3026
  let jsonText = text.trim();
@@ -3409,11 +3030,29 @@ var LLM = class {
3409
3030
  jsonText = jsonText.replace(/^```\s*\n?/, "").replace(/\n?```\s*$/, "");
3410
3031
  }
3411
3032
  const firstBrace = jsonText.indexOf("{");
3033
+ const firstBracket = jsonText.indexOf("[");
3412
3034
  const lastBrace = jsonText.lastIndexOf("}");
3413
- if (firstBrace !== -1 && lastBrace !== -1 && firstBrace < lastBrace) {
3414
- jsonText = jsonText.substring(firstBrace, lastBrace + 1);
3035
+ const lastBracket = jsonText.lastIndexOf("]");
3036
+ let startIdx = -1;
3037
+ let endIdx = -1;
3038
+ if (firstBrace !== -1 && (firstBracket === -1 || firstBrace < firstBracket)) {
3039
+ startIdx = firstBrace;
3040
+ endIdx = lastBrace;
3041
+ } else if (firstBracket !== -1) {
3042
+ startIdx = firstBracket;
3043
+ endIdx = lastBracket;
3044
+ }
3045
+ if (startIdx !== -1 && endIdx !== -1 && startIdx < endIdx) {
3046
+ jsonText = jsonText.substring(startIdx, endIdx + 1);
3047
+ }
3048
+ try {
3049
+ const repairedJson = jsonrepair(jsonText);
3050
+ return JSON.parse(repairedJson);
3051
+ } catch (error) {
3052
+ throw new Error(`Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}
3053
+
3054
+ Original text: ${jsonText.substring(0, 200)}...`);
3415
3055
  }
3416
- return JSON.parse(jsonText);
3417
3056
  }
3418
3057
  };
3419
3058
 
@@ -4026,7 +3665,7 @@ var BaseLLM = class {
4026
3665
  logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
4027
3666
  logger.file("\n=============================\nmatch text components system prompt:", prompts.system);
4028
3667
  logCollector?.info("Matching components from text response...");
4029
- const rawResponse = await LLM.stream(
3668
+ const result = await LLM.stream(
4030
3669
  {
4031
3670
  sys: prompts.system,
4032
3671
  user: prompts.user
@@ -4037,60 +3676,12 @@ var BaseLLM = class {
4037
3676
  temperature: 0.2,
4038
3677
  apiKey: this.getApiKey(apiKey)
4039
3678
  },
4040
- false
4041
- // Don't parse as JSON yet, get raw response
3679
+ true
3680
+ // Parse as JSON
4042
3681
  );
4043
- logger.debug(`[${this.getProviderName()}] Raw component matching response length: ${rawResponse?.length || 0}`);
4044
- let result;
4045
- try {
4046
- let cleanedResponse = rawResponse || "";
4047
- cleanedResponse = cleanedResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
4048
- const jsonMatch = cleanedResponse.match(/\{[\s\S]*\}/);
4049
- if (jsonMatch) {
4050
- cleanedResponse = jsonMatch[0];
4051
- }
4052
- result = JSON.parse(cleanedResponse);
4053
- } catch (parseError) {
4054
- logger.error(`[${this.getProviderName()}] Failed to parse component matching JSON response`);
4055
- const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
4056
- const posMatch = errorMsg.match(/position (\d+)/);
4057
- const errorPos = posMatch ? parseInt(posMatch[1]) : -1;
4058
- if (errorPos > 0 && rawResponse) {
4059
- const start = Math.max(0, errorPos - 200);
4060
- const end = Math.min(rawResponse.length, errorPos + 200);
4061
- logger.debug(`[${this.getProviderName()}] Error context (position ${errorPos}):`);
4062
- logger.debug(rawResponse.substring(start, end));
4063
- logger.debug(" ".repeat(Math.min(200, errorPos - start)) + "^--- Error here");
4064
- }
4065
- logger.debug(`[${this.getProviderName()}] Raw response (first 2000 chars):`, rawResponse?.substring(0, 2e3));
4066
- logger.debug(`[${this.getProviderName()}] Parse error:`, parseError);
4067
- logCollector?.error(`Failed to parse component matching response: ${errorMsg}`);
4068
- try {
4069
- logger.info(`[${this.getProviderName()}] Attempting aggressive JSON cleanup...`);
4070
- let aggressive = rawResponse || "";
4071
- aggressive = aggressive.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
4072
- const match = aggressive.match(/\{[\s\S]*\}/);
4073
- if (match) {
4074
- aggressive = match[0];
4075
- }
4076
- aggressive = aggressive.replace(/,(\s*[}\]])/g, "$1");
4077
- result = JSON.parse(aggressive);
4078
- logger.info(`[${this.getProviderName()}] Aggressive cleanup succeeded!`);
4079
- } catch (secondError) {
4080
- logger.error(`[${this.getProviderName()}] Aggressive cleanup also failed`);
4081
- return {
4082
- components: [],
4083
- selectedLayout: "MultiComponentContainer",
4084
- selectedLayoutId: "",
4085
- selectedLayoutComponent: null,
4086
- layoutReasoning: "No layout selected",
4087
- actions: []
4088
- };
4089
- }
4090
- }
3682
+ logger.debug(`[${this.getProviderName()}] Component matching response parsed successfully`);
4091
3683
  const matchedComponents = result.matchedComponents || [];
4092
- const selectedLayout = result.selectedLayout || "MultiComponentContainer";
4093
- const selectedLayoutId = result.selectedLayoutId || "";
3684
+ const selectedLayoutId = result.selectedLayoutId || "multi-component-container";
4094
3685
  const layoutReasoning = result.layoutReasoning || "No layout reasoning provided";
4095
3686
  const rawActions = result.actions || [];
4096
3687
  const actions = convertQuestionsToActions(rawActions);
@@ -4102,11 +3693,11 @@ var BaseLLM = class {
4102
3693
  }
4103
3694
  }
4104
3695
  logger.info(`[${this.getProviderName()}] Matched ${matchedComponents.length} components from text response`);
4105
- logger.info(`[${this.getProviderName()}] Selected layout: ${selectedLayout} (ID: ${selectedLayoutId})`);
3696
+ logger.info(`[${this.getProviderName()}] Selected layout: (ID: ${selectedLayoutId})`);
4106
3697
  logger.info(`[${this.getProviderName()}] Layout reasoning: ${layoutReasoning}`);
4107
3698
  logger.info(`[${this.getProviderName()}] Generated ${actions.length} follow-up actions`);
4108
3699
  if (matchedComponents.length > 0) {
4109
- logCollector?.info(`Matched ${matchedComponents.length} components for visualization using ${selectedLayout}`);
3700
+ logCollector?.info(`Matched ${matchedComponents.length} components for visualization `);
4110
3701
  logCollector?.info(`Layout reasoning: ${layoutReasoning}`);
4111
3702
  matchedComponents.forEach((comp, idx) => {
4112
3703
  logCollector?.info(` ${idx + 1}. ${comp.componentName} (${comp.componentType}): ${comp.reasoning}`);
@@ -4141,7 +3732,6 @@ var BaseLLM = class {
4141
3732
  }).filter(Boolean);
4142
3733
  return {
4143
3734
  components: finalComponents,
4144
- selectedLayout,
4145
3735
  selectedLayoutId,
4146
3736
  selectedLayoutComponent,
4147
3737
  layoutReasoning,
@@ -4149,15 +3739,13 @@ var BaseLLM = class {
4149
3739
  };
4150
3740
  } catch (error) {
4151
3741
  const errorMsg = error instanceof Error ? error.message : String(error);
4152
- logger.error(`[${this.getProviderName()}] Error matching components from text response: ${errorMsg}`);
4153
- logger.debug(`[${this.getProviderName()}] Component matching error details:`, error);
4154
- logCollector?.error(`Error matching components: ${errorMsg}`);
3742
+ logger.error(`[${this.getProviderName()}] Error matching components: ${errorMsg}`);
3743
+ logCollector?.error(`Failed to match components: ${errorMsg}`);
4155
3744
  return {
4156
3745
  components: [],
4157
- selectedLayout: "MultiComponentContainer",
4158
3746
  selectedLayoutId: "",
4159
3747
  selectedLayoutComponent: null,
4160
- layoutReasoning: "Error occurred during component matching",
3748
+ layoutReasoning: "Failed to match components due to parsing error",
4161
3749
  actions: []
4162
3750
  };
4163
3751
  }
@@ -4424,7 +4012,7 @@ ${errorMsg}
4424
4012
  container_componet = {
4425
4013
  ...selectedLayoutComponent,
4426
4014
  id: `${selectedLayoutComponent.id}_${Date.now()}`,
4427
- description: layoutReasoning,
4015
+ // Make ID unique for each instance
4428
4016
  props: {
4429
4017
  ...selectedLayoutComponent.props,
4430
4018
  config: {
@@ -4775,7 +4363,7 @@ ${errorMsg}
4775
4363
  };
4776
4364
 
4777
4365
  // src/userResponse/groq.ts
4778
- import_dotenv.default.config();
4366
+ dotenv.config();
4779
4367
  var GroqLLM = class extends BaseLLM {
4780
4368
  constructor(config) {
4781
4369
  super(config);
@@ -4793,8 +4381,8 @@ var GroqLLM = class extends BaseLLM {
4793
4381
  var groqLLM = new GroqLLM();
4794
4382
 
4795
4383
  // src/userResponse/anthropic.ts
4796
- var import_dotenv2 = __toESM(require_main());
4797
- import_dotenv2.default.config();
4384
+ import dotenv2 from "dotenv";
4385
+ dotenv2.config();
4798
4386
  var AnthropicLLM = class extends BaseLLM {
4799
4387
  constructor(config) {
4800
4388
  super(config);
@@ -4812,8 +4400,8 @@ var AnthropicLLM = class extends BaseLLM {
4812
4400
  var anthropicLLM = new AnthropicLLM();
4813
4401
 
4814
4402
  // src/userResponse/index.ts
4815
- var import_dotenv3 = __toESM(require_main());
4816
- import_dotenv3.default.config();
4403
+ import dotenv3 from "dotenv";
4404
+ dotenv3.config();
4817
4405
  function getLLMProviders() {
4818
4406
  const envProviders = process.env.LLM_PROVIDERS;
4819
4407
  const DEFAULT_PROVIDERS = ["anthropic", "groq"];
@@ -7271,7 +6859,7 @@ var SuperatomSDK = class {
7271
6859
  url.searchParams.set("projectId", this.projectId);
7272
6860
  url.searchParams.set("userId", this.userId);
7273
6861
  url.searchParams.set("type", this.type);
7274
- logger.info(`Connecting to WebSocket: ${url.host}`);
6862
+ logger.info(`Connecting to WebSocket: ${url.toString()}`);
7275
6863
  this.ws = createWebSocket(url.toString());
7276
6864
  this.ws.addEventListener("open", () => {
7277
6865
  this.connected = true;