@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.js CHANGED
@@ -8,9 +8,6 @@ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
8
  var __esm = (fn, res) => function __init() {
9
9
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
10
  };
11
- var __commonJS = (cb, mod) => function __require() {
12
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
13
- };
14
11
  var __export = (target, all) => {
15
12
  for (var name in all)
16
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -33,404 +30,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
33
30
  ));
34
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
35
32
 
36
- // node_modules/dotenv/package.json
37
- var require_package = __commonJS({
38
- "node_modules/dotenv/package.json"(exports2, module2) {
39
- module2.exports = {
40
- name: "dotenv",
41
- version: "17.2.3",
42
- description: "Loads environment variables from .env file",
43
- main: "lib/main.js",
44
- types: "lib/main.d.ts",
45
- exports: {
46
- ".": {
47
- types: "./lib/main.d.ts",
48
- require: "./lib/main.js",
49
- default: "./lib/main.js"
50
- },
51
- "./config": "./config.js",
52
- "./config.js": "./config.js",
53
- "./lib/env-options": "./lib/env-options.js",
54
- "./lib/env-options.js": "./lib/env-options.js",
55
- "./lib/cli-options": "./lib/cli-options.js",
56
- "./lib/cli-options.js": "./lib/cli-options.js",
57
- "./package.json": "./package.json"
58
- },
59
- scripts: {
60
- "dts-check": "tsc --project tests/types/tsconfig.json",
61
- lint: "standard",
62
- pretest: "npm run lint && npm run dts-check",
63
- test: "tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000",
64
- "test:coverage": "tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
65
- prerelease: "npm test",
66
- release: "standard-version"
67
- },
68
- repository: {
69
- type: "git",
70
- url: "git://github.com/motdotla/dotenv.git"
71
- },
72
- homepage: "https://github.com/motdotla/dotenv#readme",
73
- funding: "https://dotenvx.com",
74
- keywords: [
75
- "dotenv",
76
- "env",
77
- ".env",
78
- "environment",
79
- "variables",
80
- "config",
81
- "settings"
82
- ],
83
- readmeFilename: "README.md",
84
- license: "BSD-2-Clause",
85
- devDependencies: {
86
- "@types/node": "^18.11.3",
87
- decache: "^4.6.2",
88
- sinon: "^14.0.1",
89
- standard: "^17.0.0",
90
- "standard-version": "^9.5.0",
91
- tap: "^19.2.0",
92
- typescript: "^4.8.4"
93
- },
94
- engines: {
95
- node: ">=12"
96
- },
97
- browser: {
98
- fs: false
99
- }
100
- };
101
- }
102
- });
103
-
104
- // node_modules/dotenv/lib/main.js
105
- var require_main = __commonJS({
106
- "node_modules/dotenv/lib/main.js"(exports2, module2) {
107
- "use strict";
108
- var fs8 = require("fs");
109
- var path7 = require("path");
110
- var os4 = require("os");
111
- var crypto2 = require("crypto");
112
- var packageJson = require_package();
113
- var version = packageJson.version;
114
- var TIPS = [
115
- "\u{1F510} encrypt with Dotenvx: https://dotenvx.com",
116
- "\u{1F510} prevent committing .env to code: https://dotenvx.com/precommit",
117
- "\u{1F510} prevent building .env in docker: https://dotenvx.com/prebuild",
118
- "\u{1F4E1} add observability to secrets: https://dotenvx.com/ops",
119
- "\u{1F465} sync secrets across teammates & machines: https://dotenvx.com/ops",
120
- "\u{1F5C2}\uFE0F backup and recover secrets: https://dotenvx.com/ops",
121
- "\u2705 audit secrets and track compliance: https://dotenvx.com/ops",
122
- "\u{1F504} add secrets lifecycle management: https://dotenvx.com/ops",
123
- "\u{1F511} add access controls to secrets: https://dotenvx.com/ops",
124
- "\u{1F6E0}\uFE0F run anywhere with `dotenvx run -- yourcommand`",
125
- "\u2699\uFE0F specify custom .env file path with { path: '/custom/path/.env' }",
126
- "\u2699\uFE0F enable debug logging with { debug: true }",
127
- "\u2699\uFE0F override existing env vars with { override: true }",
128
- "\u2699\uFE0F suppress all logs with { quiet: true }",
129
- "\u2699\uFE0F write to custom object with { processEnv: myObject }",
130
- "\u2699\uFE0F load multiple .env files with { path: ['.env.local', '.env'] }"
131
- ];
132
- function _getRandomTip() {
133
- return TIPS[Math.floor(Math.random() * TIPS.length)];
134
- }
135
- function parseBoolean(value) {
136
- if (typeof value === "string") {
137
- return !["false", "0", "no", "off", ""].includes(value.toLowerCase());
138
- }
139
- return Boolean(value);
140
- }
141
- function supportsAnsi() {
142
- return process.stdout.isTTY;
143
- }
144
- function dim(text) {
145
- return supportsAnsi() ? `\x1B[2m${text}\x1B[0m` : text;
146
- }
147
- var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
148
- function parse(src) {
149
- const obj = {};
150
- let lines = src.toString();
151
- lines = lines.replace(/\r\n?/mg, "\n");
152
- let match;
153
- while ((match = LINE.exec(lines)) != null) {
154
- const key = match[1];
155
- let value = match[2] || "";
156
- value = value.trim();
157
- const maybeQuote = value[0];
158
- value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
159
- if (maybeQuote === '"') {
160
- value = value.replace(/\\n/g, "\n");
161
- value = value.replace(/\\r/g, "\r");
162
- }
163
- obj[key] = value;
164
- }
165
- return obj;
166
- }
167
- function _parseVault(options) {
168
- options = options || {};
169
- const vaultPath = _vaultPath(options);
170
- options.path = vaultPath;
171
- const result = DotenvModule.configDotenv(options);
172
- if (!result.parsed) {
173
- const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
174
- err.code = "MISSING_DATA";
175
- throw err;
176
- }
177
- const keys = _dotenvKey(options).split(",");
178
- const length = keys.length;
179
- let decrypted;
180
- for (let i = 0; i < length; i++) {
181
- try {
182
- const key = keys[i].trim();
183
- const attrs = _instructions(result, key);
184
- decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
185
- break;
186
- } catch (error) {
187
- if (i + 1 >= length) {
188
- throw error;
189
- }
190
- }
191
- }
192
- return DotenvModule.parse(decrypted);
193
- }
194
- function _warn(message) {
195
- console.error(`[dotenv@${version}][WARN] ${message}`);
196
- }
197
- function _debug(message) {
198
- console.log(`[dotenv@${version}][DEBUG] ${message}`);
199
- }
200
- function _log(message) {
201
- console.log(`[dotenv@${version}] ${message}`);
202
- }
203
- function _dotenvKey(options) {
204
- if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
205
- return options.DOTENV_KEY;
206
- }
207
- if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
208
- return process.env.DOTENV_KEY;
209
- }
210
- return "";
211
- }
212
- function _instructions(result, dotenvKey) {
213
- let uri;
214
- try {
215
- uri = new URL(dotenvKey);
216
- } catch (error) {
217
- if (error.code === "ERR_INVALID_URL") {
218
- 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");
219
- err.code = "INVALID_DOTENV_KEY";
220
- throw err;
221
- }
222
- throw error;
223
- }
224
- const key = uri.password;
225
- if (!key) {
226
- const err = new Error("INVALID_DOTENV_KEY: Missing key part");
227
- err.code = "INVALID_DOTENV_KEY";
228
- throw err;
229
- }
230
- const environment = uri.searchParams.get("environment");
231
- if (!environment) {
232
- const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
233
- err.code = "INVALID_DOTENV_KEY";
234
- throw err;
235
- }
236
- const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
237
- const ciphertext = result.parsed[environmentKey];
238
- if (!ciphertext) {
239
- const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
240
- err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
241
- throw err;
242
- }
243
- return { ciphertext, key };
244
- }
245
- function _vaultPath(options) {
246
- let possibleVaultPath = null;
247
- if (options && options.path && options.path.length > 0) {
248
- if (Array.isArray(options.path)) {
249
- for (const filepath of options.path) {
250
- if (fs8.existsSync(filepath)) {
251
- possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
252
- }
253
- }
254
- } else {
255
- possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
256
- }
257
- } else {
258
- possibleVaultPath = path7.resolve(process.cwd(), ".env.vault");
259
- }
260
- if (fs8.existsSync(possibleVaultPath)) {
261
- return possibleVaultPath;
262
- }
263
- return null;
264
- }
265
- function _resolveHome(envPath) {
266
- return envPath[0] === "~" ? path7.join(os4.homedir(), envPath.slice(1)) : envPath;
267
- }
268
- function _configVault(options) {
269
- const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
270
- const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options && options.quiet);
271
- if (debug || !quiet) {
272
- _log("Loading env from encrypted .env.vault");
273
- }
274
- const parsed = DotenvModule._parseVault(options);
275
- let processEnv = process.env;
276
- if (options && options.processEnv != null) {
277
- processEnv = options.processEnv;
278
- }
279
- DotenvModule.populate(processEnv, parsed, options);
280
- return { parsed };
281
- }
282
- function configDotenv(options) {
283
- const dotenvPath = path7.resolve(process.cwd(), ".env");
284
- let encoding = "utf8";
285
- let processEnv = process.env;
286
- if (options && options.processEnv != null) {
287
- processEnv = options.processEnv;
288
- }
289
- let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options && options.debug);
290
- let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options && options.quiet);
291
- if (options && options.encoding) {
292
- encoding = options.encoding;
293
- } else {
294
- if (debug) {
295
- _debug("No encoding is specified. UTF-8 is used by default");
296
- }
297
- }
298
- let optionPaths = [dotenvPath];
299
- if (options && options.path) {
300
- if (!Array.isArray(options.path)) {
301
- optionPaths = [_resolveHome(options.path)];
302
- } else {
303
- optionPaths = [];
304
- for (const filepath of options.path) {
305
- optionPaths.push(_resolveHome(filepath));
306
- }
307
- }
308
- }
309
- let lastError;
310
- const parsedAll = {};
311
- for (const path8 of optionPaths) {
312
- try {
313
- const parsed = DotenvModule.parse(fs8.readFileSync(path8, { encoding }));
314
- DotenvModule.populate(parsedAll, parsed, options);
315
- } catch (e) {
316
- if (debug) {
317
- _debug(`Failed to load ${path8} ${e.message}`);
318
- }
319
- lastError = e;
320
- }
321
- }
322
- const populated = DotenvModule.populate(processEnv, parsedAll, options);
323
- debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug);
324
- quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
325
- if (debug || !quiet) {
326
- const keysCount = Object.keys(populated).length;
327
- const shortPaths = [];
328
- for (const filePath of optionPaths) {
329
- try {
330
- const relative = path7.relative(process.cwd(), filePath);
331
- shortPaths.push(relative);
332
- } catch (e) {
333
- if (debug) {
334
- _debug(`Failed to load ${filePath} ${e.message}`);
335
- }
336
- lastError = e;
337
- }
338
- }
339
- _log(`injecting env (${keysCount}) from ${shortPaths.join(",")} ${dim(`-- tip: ${_getRandomTip()}`)}`);
340
- }
341
- if (lastError) {
342
- return { parsed: parsedAll, error: lastError };
343
- } else {
344
- return { parsed: parsedAll };
345
- }
346
- }
347
- function config(options) {
348
- if (_dotenvKey(options).length === 0) {
349
- return DotenvModule.configDotenv(options);
350
- }
351
- const vaultPath = _vaultPath(options);
352
- if (!vaultPath) {
353
- _warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
354
- return DotenvModule.configDotenv(options);
355
- }
356
- return DotenvModule._configVault(options);
357
- }
358
- function decrypt(encrypted, keyStr) {
359
- const key = Buffer.from(keyStr.slice(-64), "hex");
360
- let ciphertext = Buffer.from(encrypted, "base64");
361
- const nonce = ciphertext.subarray(0, 12);
362
- const authTag = ciphertext.subarray(-16);
363
- ciphertext = ciphertext.subarray(12, -16);
364
- try {
365
- const aesgcm = crypto2.createDecipheriv("aes-256-gcm", key, nonce);
366
- aesgcm.setAuthTag(authTag);
367
- return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
368
- } catch (error) {
369
- const isRange = error instanceof RangeError;
370
- const invalidKeyLength = error.message === "Invalid key length";
371
- const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
372
- if (isRange || invalidKeyLength) {
373
- const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
374
- err.code = "INVALID_DOTENV_KEY";
375
- throw err;
376
- } else if (decryptionFailed) {
377
- const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
378
- err.code = "DECRYPTION_FAILED";
379
- throw err;
380
- } else {
381
- throw error;
382
- }
383
- }
384
- }
385
- function populate(processEnv, parsed, options = {}) {
386
- const debug = Boolean(options && options.debug);
387
- const override = Boolean(options && options.override);
388
- const populated = {};
389
- if (typeof parsed !== "object") {
390
- const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
391
- err.code = "OBJECT_REQUIRED";
392
- throw err;
393
- }
394
- for (const key of Object.keys(parsed)) {
395
- if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
396
- if (override === true) {
397
- processEnv[key] = parsed[key];
398
- populated[key] = parsed[key];
399
- }
400
- if (debug) {
401
- if (override === true) {
402
- _debug(`"${key}" is already defined and WAS overwritten`);
403
- } else {
404
- _debug(`"${key}" is already defined and was NOT overwritten`);
405
- }
406
- }
407
- } else {
408
- processEnv[key] = parsed[key];
409
- populated[key] = parsed[key];
410
- }
411
- }
412
- return populated;
413
- }
414
- var DotenvModule = {
415
- configDotenv,
416
- _configVault,
417
- _parseVault,
418
- config,
419
- decrypt,
420
- parse,
421
- populate
422
- };
423
- module2.exports.configDotenv = DotenvModule.configDotenv;
424
- module2.exports._configVault = DotenvModule._configVault;
425
- module2.exports._parseVault = DotenvModule._parseVault;
426
- module2.exports.config = DotenvModule.config;
427
- module2.exports.decrypt = DotenvModule.decrypt;
428
- module2.exports.parse = DotenvModule.parse;
429
- module2.exports.populate = DotenvModule.populate;
430
- module2.exports = DotenvModule;
431
- }
432
- });
433
-
434
33
  // src/userResponse/utils.ts
435
34
  var utils_exports = {};
436
35
  __export(utils_exports, {
@@ -861,7 +460,7 @@ var UserPromptSuggestionsMessageSchema = import_zod3.z.object({
861
460
  payload: UserPromptSuggestionsPayloadSchema
862
461
  });
863
462
  var ComponentPropsSchema = import_zod3.z.object({
864
- query: import_zod3.z.string().optional(),
463
+ query: import_zod3.z.string().or(import_zod3.z.object({})).optional(),
865
464
  title: import_zod3.z.string().optional(),
866
465
  description: import_zod3.z.string().optional(),
867
466
  config: import_zod3.z.record(import_zod3.z.unknown()).optional(),
@@ -2060,7 +1659,7 @@ function sendDataResponse3(id, res, sendMessage, clientId) {
2060
1659
  }
2061
1660
 
2062
1661
  // src/userResponse/groq.ts
2063
- var import_dotenv = __toESM(require_main());
1662
+ var import_dotenv = __toESM(require("dotenv"));
2064
1663
 
2065
1664
  // src/userResponse/base-llm.ts
2066
1665
  init_utils();
@@ -2688,6 +2287,7 @@ When the user asks about data
2688
2287
 
2689
2288
  After analyzing the query results, you MUST suggest appropriate dashboard components for displaying the data. Use this format:
2690
2289
 
2290
+ <DashboardComponents>
2691
2291
  **Dashboard Components:**
2692
2292
  Format: \`{number}.{component_type} : {clear reasoning}\`
2693
2293
 
@@ -2696,9 +2296,9 @@ Format: \`{number}.{component_type} : {clear reasoning}\`
2696
2296
  1. Analyze the query results structure and data type
2697
2297
  2. Suggest components that would best visualize the data
2698
2298
  3. Each component suggestion must be on a new line
2299
+ </DashboardComponents>
2699
2300
 
2700
-
2701
- IMPORTANT: Always include the **Dashboard Components:** section with at least one component suggestion when data is returned.
2301
+ IMPORTANT: Always wrap component suggestions with <DashboardComponents> tags and include at least one component suggestion when data is returned.
2702
2302
 
2703
2303
  ## Output Format
2704
2304
 
@@ -2706,7 +2306,7 @@ Respond with plain text that includes:
2706
2306
 
2707
2307
  1. **Query Analysis** (if applicable): Brief explanation of what data was fetched
2708
2308
  2. **Results Summary**: Present the data in a clear, readable format
2709
- 3. **Dashboard Components**: List suggested components in the c1:type format
2309
+ 3. **Dashboard Components**: List suggested components wrapped in <DashboardComponents> tags
2710
2310
 
2711
2311
 
2712
2312
  **CRITICAL:**
@@ -2783,39 +2383,22 @@ You will receive a text response containing:
2783
2383
  3. **Dashboard Components:** suggestions (1:component_type : reasoning format)
2784
2384
 
2785
2385
  Your job is to:
2786
- 1. **DISCOVER and SELECT the best dashboard layout component** from the available components list
2787
- 2. Parse the component suggestions from the text response
2788
- 3. Match each suggestion with an actual component from the available list
2789
- 4. Generate the RIGHT NUMBER of components to fit the selected layout perfectly (based on the layout component's description)
2790
- 5. Generate proper props to **visualize the analysis results** that were already fetched
2791
- 6. **Generate intelligent follow-up questions (actions)** that the user might naturally ask next based on the data analysis
2386
+ 1. **Parse the component suggestions** from the text response (format: 1:component_type : reasoning)
2387
+ 2. **Match each suggestion with an actual component** from the available list
2388
+ 3. **Generate proper props** for each matched component to **visualize the analysis results** that were already fetched
2389
+ 4. **SELECT the best dashboard layout component** that can accommodate all the matched components
2390
+ 5. **Generate intelligent follow-up questions (actions)** that the user might naturally ask next based on the data analysis
2792
2391
 
2793
2392
  **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.
2794
2393
 
2795
-
2796
-
2797
- ## Layout Component Discovery
2798
- **Find layout components** by looking for components with \`type: "DashboardLayout"\`
2799
-
2800
- ## Layout Selection Logic
2801
- 1. **Read each layout's description** to understand:
2802
- - What structure it provides
2803
- - When it's best used (e.g., comprehensive analysis vs focused analysis)
2804
- - The exact number and types of components it requires
2805
- 2. **Select the best layout** based on:
2806
- - Which layout structure best fits the analysis needs
2807
- - The component suggestions from the text response
2808
- - The user question and data complexity
2809
- 3. **Generate EXACTLY the components specified** in the selected layout's description
2810
-
2811
- **IMPORTANT:** Always prefer structured dashboard layouts when available. The layout component's description will tell you exactly what components to generate.
2394
+ **APPROACH**: First match all the components suggested in the text response, THEN find the layout that best fits those components.
2812
2395
 
2813
2396
  ## Available Components
2814
2397
 
2815
2398
  {{AVAILABLE_COMPONENTS}}
2816
2399
 
2817
- ## Component Matching Rules
2818
- For each component suggestion (c1, c2, c3, etc.):
2400
+ ## Component Matching Rules (STEP 1)
2401
+ For each component suggestion (c1, c2, c3, etc.) from the text response:
2819
2402
 
2820
2403
  1. **Match by type**: Find components whose \`type\` matches the suggested component type
2821
2404
  2. **Refine by relevance**: If multiple components match, choose based on:
@@ -2823,6 +2406,24 @@ For each component suggestion (c1, c2, c3, etc.):
2823
2406
  - Best fit for the data being visualized
2824
2407
  3. **Fallback**: If no exact type match, find the closest alternative
2825
2408
 
2409
+ ## Layout Selection Logic (STEP 2 - After Matching Components)
2410
+
2411
+ **After you have matched all components**, select the best dashboard layout:
2412
+
2413
+ 1. **Find layout components** by looking for components with \`type: "DashboardLayout"\` in the available components list
2414
+ 2. **Read each layout's description** to understand:
2415
+ - What structure it provides
2416
+ - When it's best used (e.g., comprehensive analysis vs focused analysis)
2417
+ - The number and types of components it can accommodate
2418
+ 3. **Select the best layout** based on:
2419
+ - Which layout can best display ALL the matched components
2420
+ - The layout's capacity (how many components it supports)
2421
+ - The types of matched components (KPI, charts, tables, etc.)
2422
+ - The user question and data complexity
2423
+ 4. **If no specific layout fits**, fall back to "MultiComponentContainer" as the default layout
2424
+
2425
+ **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.
2426
+
2826
2427
  ## Props Generation Rules
2827
2428
 
2828
2429
  For each matched component, generate complete props:
@@ -2935,7 +2536,6 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
2935
2536
 
2936
2537
  \`\`\`json
2937
2538
  {
2938
- "selectedLayout": "Name of the selected layout component from available components",
2939
2539
  "selectedLayoutId": "id_of_the_selected_layout_component",
2940
2540
  "layoutReasoning": "Why this layout was selected based on its description and the analysis needs",
2941
2541
  "matchedComponents": [
@@ -2967,13 +2567,14 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
2967
2567
  \`\`\`
2968
2568
 
2969
2569
  **CRITICAL:**
2970
- - \`selectedLayout\` MUST be the NAME of a layout component from the available components list (must have type "DashboardLayout")
2971
- - \`selectedLayoutId\` MUST be the ID of the selected layout component
2570
+ - \`matchedComponents\` MUST include ALL components suggested in the text response (match them first!)
2571
+ - \`selectedLayoutId\` MUST be the ID of the selected layout component (must have type "DashboardLayout")
2972
2572
  - \`layoutReasoning\` MUST explain:
2973
2573
  - Why you chose this specific layout component
2974
- - How its structure (from its description) matches the analysis needs
2975
- - What components it requires based on its description
2976
- - \`matchedComponents\` array length and types MUST match what the selected layout's description specifies
2574
+ - How many components you matched (e.g., "Matched 3 components: 1 KPI, 1 chart, 1 table")
2575
+ - Why this layout is the best fit for displaying these specific matched components
2576
+ - What makes this layout appropriate for the component types and count
2577
+ - The layout selection happens AFTER component matching - don't force components to fit a pre-selected layout
2977
2578
  - \`actions\` MUST be an array of 4-5 intelligent follow-up questions based on the analysis
2978
2579
  - Return ONLY valid JSON (no markdown code blocks, no text before/after)
2979
2580
  - Generate complete props for each component
@@ -3169,6 +2770,7 @@ var promptLoader = new PromptLoader({
3169
2770
  // src/llm.ts
3170
2771
  var import_sdk = __toESM(require("@anthropic-ai/sdk"));
3171
2772
  var import_groq_sdk = __toESM(require("groq-sdk"));
2773
+ var import_jsonrepair = require("jsonrepair");
3172
2774
  var LLM = class {
3173
2775
  /* Get a complete text response from an LLM (Anthropic or Groq) */
3174
2776
  static async text(messages, options = {}) {
@@ -3290,65 +2892,110 @@ var LLM = class {
3290
2892
  let finalText = "";
3291
2893
  while (iterations < maxIterations) {
3292
2894
  iterations++;
3293
- const response = await client.messages.create({
2895
+ const stream = await client.messages.create({
3294
2896
  model: modelName,
3295
2897
  max_tokens: options.maxTokens || 4e3,
3296
2898
  temperature: options.temperature,
3297
2899
  system: messages.sys,
3298
2900
  messages: conversationMessages,
3299
- tools
2901
+ tools,
2902
+ stream: true
2903
+ // Enable streaming
3300
2904
  });
3301
- if (response.stop_reason === "end_turn") {
3302
- const textBlock = response.content.find((block) => block.type === "text");
3303
- if (textBlock && textBlock.type === "text") {
3304
- finalText = textBlock.text;
3305
- if (options.partial) {
3306
- options.partial(finalText);
2905
+ let stopReason = null;
2906
+ const contentBlocks = [];
2907
+ let currentTextBlock = "";
2908
+ let currentToolUse = null;
2909
+ for await (const chunk of stream) {
2910
+ if (chunk.type === "message_start") {
2911
+ contentBlocks.length = 0;
2912
+ currentTextBlock = "";
2913
+ currentToolUse = null;
2914
+ }
2915
+ if (chunk.type === "content_block_start") {
2916
+ if (chunk.content_block.type === "text") {
2917
+ currentTextBlock = "";
2918
+ } else if (chunk.content_block.type === "tool_use") {
2919
+ currentToolUse = {
2920
+ type: "tool_use",
2921
+ id: chunk.content_block.id,
2922
+ name: chunk.content_block.name,
2923
+ input: {}
2924
+ };
2925
+ }
2926
+ }
2927
+ if (chunk.type === "content_block_delta") {
2928
+ if (chunk.delta.type === "text_delta") {
2929
+ const text = chunk.delta.text;
2930
+ currentTextBlock += text;
2931
+ if (options.partial) {
2932
+ options.partial(text);
2933
+ }
2934
+ } else if (chunk.delta.type === "input_json_delta" && currentToolUse) {
2935
+ currentToolUse.inputJson = (currentToolUse.inputJson || "") + chunk.delta.partial_json;
3307
2936
  }
3308
2937
  }
2938
+ if (chunk.type === "content_block_stop") {
2939
+ if (currentTextBlock) {
2940
+ contentBlocks.push({
2941
+ type: "text",
2942
+ text: currentTextBlock
2943
+ });
2944
+ finalText = currentTextBlock;
2945
+ currentTextBlock = "";
2946
+ } else if (currentToolUse) {
2947
+ try {
2948
+ currentToolUse.input = currentToolUse.inputJson ? JSON.parse(currentToolUse.inputJson) : {};
2949
+ } catch (error) {
2950
+ currentToolUse.input = {};
2951
+ }
2952
+ delete currentToolUse.inputJson;
2953
+ contentBlocks.push(currentToolUse);
2954
+ currentToolUse = null;
2955
+ }
2956
+ }
2957
+ if (chunk.type === "message_delta") {
2958
+ stopReason = chunk.delta.stop_reason || stopReason;
2959
+ }
2960
+ if (chunk.type === "message_stop") {
2961
+ break;
2962
+ }
2963
+ }
2964
+ if (stopReason === "end_turn") {
3309
2965
  break;
3310
2966
  }
3311
- if (response.stop_reason === "tool_use") {
3312
- const toolUses = response.content.filter((block) => block.type === "tool_use");
2967
+ if (stopReason === "tool_use") {
2968
+ const toolUses = contentBlocks.filter((block) => block.type === "tool_use");
3313
2969
  if (toolUses.length === 0) {
3314
2970
  break;
3315
2971
  }
3316
2972
  conversationMessages.push({
3317
2973
  role: "assistant",
3318
- content: response.content
2974
+ content: contentBlocks
3319
2975
  });
3320
2976
  const toolResults = {
3321
2977
  role: "user",
3322
2978
  content: []
3323
2979
  };
3324
2980
  for (const toolUse of toolUses) {
3325
- if (toolUse.type === "tool_use") {
3326
- try {
3327
- const result = await toolHandler(toolUse.name, toolUse.input);
3328
- toolResults.content.push({
3329
- type: "tool_result",
3330
- tool_use_id: toolUse.id,
3331
- content: typeof result === "string" ? result : JSON.stringify(result)
3332
- });
3333
- } catch (error) {
3334
- toolResults.content.push({
3335
- type: "tool_result",
3336
- tool_use_id: toolUse.id,
3337
- content: error instanceof Error ? error.message : String(error),
3338
- is_error: true
3339
- });
3340
- }
2981
+ try {
2982
+ const result = await toolHandler(toolUse.name, toolUse.input);
2983
+ toolResults.content.push({
2984
+ type: "tool_result",
2985
+ tool_use_id: toolUse.id,
2986
+ content: typeof result === "string" ? result : JSON.stringify(result)
2987
+ });
2988
+ } catch (error) {
2989
+ toolResults.content.push({
2990
+ type: "tool_result",
2991
+ tool_use_id: toolUse.id,
2992
+ content: error instanceof Error ? error.message : String(error),
2993
+ is_error: true
2994
+ });
3341
2995
  }
3342
2996
  }
3343
2997
  conversationMessages.push(toolResults);
3344
2998
  } else {
3345
- const textBlock = response.content.find((block) => block.type === "text");
3346
- if (textBlock && textBlock.type === "text") {
3347
- finalText = textBlock.text;
3348
- if (options.partial) {
3349
- options.partial(finalText);
3350
- }
3351
- }
3352
2999
  break;
3353
3000
  }
3354
3001
  }
@@ -3411,9 +3058,9 @@ var LLM = class {
3411
3058
  // ============================================================
3412
3059
  /**
3413
3060
  * Parse JSON string, handling markdown code blocks and surrounding text
3414
- * Enhanced version from anthropic.ts implementation
3061
+ * Enhanced version with jsonrepair to handle malformed JSON from LLMs
3415
3062
  * @param text - Text that may contain JSON wrapped in ```json...``` or with surrounding text
3416
- * @returns Parsed JSON object
3063
+ * @returns Parsed JSON object or array
3417
3064
  */
3418
3065
  static _parseJSON(text) {
3419
3066
  let jsonText = text.trim();
@@ -3423,11 +3070,29 @@ var LLM = class {
3423
3070
  jsonText = jsonText.replace(/^```\s*\n?/, "").replace(/\n?```\s*$/, "");
3424
3071
  }
3425
3072
  const firstBrace = jsonText.indexOf("{");
3073
+ const firstBracket = jsonText.indexOf("[");
3426
3074
  const lastBrace = jsonText.lastIndexOf("}");
3427
- if (firstBrace !== -1 && lastBrace !== -1 && firstBrace < lastBrace) {
3428
- jsonText = jsonText.substring(firstBrace, lastBrace + 1);
3075
+ const lastBracket = jsonText.lastIndexOf("]");
3076
+ let startIdx = -1;
3077
+ let endIdx = -1;
3078
+ if (firstBrace !== -1 && (firstBracket === -1 || firstBrace < firstBracket)) {
3079
+ startIdx = firstBrace;
3080
+ endIdx = lastBrace;
3081
+ } else if (firstBracket !== -1) {
3082
+ startIdx = firstBracket;
3083
+ endIdx = lastBracket;
3084
+ }
3085
+ if (startIdx !== -1 && endIdx !== -1 && startIdx < endIdx) {
3086
+ jsonText = jsonText.substring(startIdx, endIdx + 1);
3087
+ }
3088
+ try {
3089
+ const repairedJson = (0, import_jsonrepair.jsonrepair)(jsonText);
3090
+ return JSON.parse(repairedJson);
3091
+ } catch (error) {
3092
+ throw new Error(`Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}
3093
+
3094
+ Original text: ${jsonText.substring(0, 200)}...`);
3429
3095
  }
3430
- return JSON.parse(jsonText);
3431
3096
  }
3432
3097
  };
3433
3098
 
@@ -4040,7 +3705,7 @@ var BaseLLM = class {
4040
3705
  logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
4041
3706
  logger.file("\n=============================\nmatch text components system prompt:", prompts.system);
4042
3707
  logCollector?.info("Matching components from text response...");
4043
- const rawResponse = await LLM.stream(
3708
+ const result = await LLM.stream(
4044
3709
  {
4045
3710
  sys: prompts.system,
4046
3711
  user: prompts.user
@@ -4051,60 +3716,12 @@ var BaseLLM = class {
4051
3716
  temperature: 0.2,
4052
3717
  apiKey: this.getApiKey(apiKey)
4053
3718
  },
4054
- false
4055
- // Don't parse as JSON yet, get raw response
3719
+ true
3720
+ // Parse as JSON
4056
3721
  );
4057
- logger.debug(`[${this.getProviderName()}] Raw component matching response length: ${rawResponse?.length || 0}`);
4058
- let result;
4059
- try {
4060
- let cleanedResponse = rawResponse || "";
4061
- cleanedResponse = cleanedResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
4062
- const jsonMatch = cleanedResponse.match(/\{[\s\S]*\}/);
4063
- if (jsonMatch) {
4064
- cleanedResponse = jsonMatch[0];
4065
- }
4066
- result = JSON.parse(cleanedResponse);
4067
- } catch (parseError) {
4068
- logger.error(`[${this.getProviderName()}] Failed to parse component matching JSON response`);
4069
- const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
4070
- const posMatch = errorMsg.match(/position (\d+)/);
4071
- const errorPos = posMatch ? parseInt(posMatch[1]) : -1;
4072
- if (errorPos > 0 && rawResponse) {
4073
- const start = Math.max(0, errorPos - 200);
4074
- const end = Math.min(rawResponse.length, errorPos + 200);
4075
- logger.debug(`[${this.getProviderName()}] Error context (position ${errorPos}):`);
4076
- logger.debug(rawResponse.substring(start, end));
4077
- logger.debug(" ".repeat(Math.min(200, errorPos - start)) + "^--- Error here");
4078
- }
4079
- logger.debug(`[${this.getProviderName()}] Raw response (first 2000 chars):`, rawResponse?.substring(0, 2e3));
4080
- logger.debug(`[${this.getProviderName()}] Parse error:`, parseError);
4081
- logCollector?.error(`Failed to parse component matching response: ${errorMsg}`);
4082
- try {
4083
- logger.info(`[${this.getProviderName()}] Attempting aggressive JSON cleanup...`);
4084
- let aggressive = rawResponse || "";
4085
- aggressive = aggressive.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
4086
- const match = aggressive.match(/\{[\s\S]*\}/);
4087
- if (match) {
4088
- aggressive = match[0];
4089
- }
4090
- aggressive = aggressive.replace(/,(\s*[}\]])/g, "$1");
4091
- result = JSON.parse(aggressive);
4092
- logger.info(`[${this.getProviderName()}] Aggressive cleanup succeeded!`);
4093
- } catch (secondError) {
4094
- logger.error(`[${this.getProviderName()}] Aggressive cleanup also failed`);
4095
- return {
4096
- components: [],
4097
- selectedLayout: "MultiComponentContainer",
4098
- selectedLayoutId: "",
4099
- selectedLayoutComponent: null,
4100
- layoutReasoning: "No layout selected",
4101
- actions: []
4102
- };
4103
- }
4104
- }
3722
+ logger.debug(`[${this.getProviderName()}] Component matching response parsed successfully`);
4105
3723
  const matchedComponents = result.matchedComponents || [];
4106
- const selectedLayout = result.selectedLayout || "MultiComponentContainer";
4107
- const selectedLayoutId = result.selectedLayoutId || "";
3724
+ const selectedLayoutId = result.selectedLayoutId || "multi-component-container";
4108
3725
  const layoutReasoning = result.layoutReasoning || "No layout reasoning provided";
4109
3726
  const rawActions = result.actions || [];
4110
3727
  const actions = convertQuestionsToActions(rawActions);
@@ -4116,11 +3733,11 @@ var BaseLLM = class {
4116
3733
  }
4117
3734
  }
4118
3735
  logger.info(`[${this.getProviderName()}] Matched ${matchedComponents.length} components from text response`);
4119
- logger.info(`[${this.getProviderName()}] Selected layout: ${selectedLayout} (ID: ${selectedLayoutId})`);
3736
+ logger.info(`[${this.getProviderName()}] Selected layout: (ID: ${selectedLayoutId})`);
4120
3737
  logger.info(`[${this.getProviderName()}] Layout reasoning: ${layoutReasoning}`);
4121
3738
  logger.info(`[${this.getProviderName()}] Generated ${actions.length} follow-up actions`);
4122
3739
  if (matchedComponents.length > 0) {
4123
- logCollector?.info(`Matched ${matchedComponents.length} components for visualization using ${selectedLayout}`);
3740
+ logCollector?.info(`Matched ${matchedComponents.length} components for visualization `);
4124
3741
  logCollector?.info(`Layout reasoning: ${layoutReasoning}`);
4125
3742
  matchedComponents.forEach((comp, idx) => {
4126
3743
  logCollector?.info(` ${idx + 1}. ${comp.componentName} (${comp.componentType}): ${comp.reasoning}`);
@@ -4155,7 +3772,6 @@ var BaseLLM = class {
4155
3772
  }).filter(Boolean);
4156
3773
  return {
4157
3774
  components: finalComponents,
4158
- selectedLayout,
4159
3775
  selectedLayoutId,
4160
3776
  selectedLayoutComponent,
4161
3777
  layoutReasoning,
@@ -4163,15 +3779,13 @@ var BaseLLM = class {
4163
3779
  };
4164
3780
  } catch (error) {
4165
3781
  const errorMsg = error instanceof Error ? error.message : String(error);
4166
- logger.error(`[${this.getProviderName()}] Error matching components from text response: ${errorMsg}`);
4167
- logger.debug(`[${this.getProviderName()}] Component matching error details:`, error);
4168
- logCollector?.error(`Error matching components: ${errorMsg}`);
3782
+ logger.error(`[${this.getProviderName()}] Error matching components: ${errorMsg}`);
3783
+ logCollector?.error(`Failed to match components: ${errorMsg}`);
4169
3784
  return {
4170
3785
  components: [],
4171
- selectedLayout: "MultiComponentContainer",
4172
3786
  selectedLayoutId: "",
4173
3787
  selectedLayoutComponent: null,
4174
- layoutReasoning: "Error occurred during component matching",
3788
+ layoutReasoning: "Failed to match components due to parsing error",
4175
3789
  actions: []
4176
3790
  };
4177
3791
  }
@@ -4438,7 +4052,7 @@ ${errorMsg}
4438
4052
  container_componet = {
4439
4053
  ...selectedLayoutComponent,
4440
4054
  id: `${selectedLayoutComponent.id}_${Date.now()}`,
4441
- description: layoutReasoning,
4055
+ // Make ID unique for each instance
4442
4056
  props: {
4443
4057
  ...selectedLayoutComponent.props,
4444
4058
  config: {
@@ -4807,7 +4421,7 @@ var GroqLLM = class extends BaseLLM {
4807
4421
  var groqLLM = new GroqLLM();
4808
4422
 
4809
4423
  // src/userResponse/anthropic.ts
4810
- var import_dotenv2 = __toESM(require_main());
4424
+ var import_dotenv2 = __toESM(require("dotenv"));
4811
4425
  import_dotenv2.default.config();
4812
4426
  var AnthropicLLM = class extends BaseLLM {
4813
4427
  constructor(config) {
@@ -4826,7 +4440,7 @@ var AnthropicLLM = class extends BaseLLM {
4826
4440
  var anthropicLLM = new AnthropicLLM();
4827
4441
 
4828
4442
  // src/userResponse/index.ts
4829
- var import_dotenv3 = __toESM(require_main());
4443
+ var import_dotenv3 = __toESM(require("dotenv"));
4830
4444
  import_dotenv3.default.config();
4831
4445
  function getLLMProviders() {
4832
4446
  const envProviders = process.env.LLM_PROVIDERS;
@@ -7285,7 +6899,7 @@ var SuperatomSDK = class {
7285
6899
  url.searchParams.set("projectId", this.projectId);
7286
6900
  url.searchParams.set("userId", this.userId);
7287
6901
  url.searchParams.set("type", this.type);
7288
- logger.info(`Connecting to WebSocket: ${url.host}`);
6902
+ logger.info(`Connecting to WebSocket: ${url.toString()}`);
7289
6903
  this.ws = createWebSocket(url.toString());
7290
6904
  this.ws.addEventListener("open", () => {
7291
6905
  this.connected = true;