@superatomai/sdk-node 0.0.9 → 0.0.11

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(),
@@ -1413,6 +1012,7 @@ var Thread = class {
1413
1012
  let assistantResponse = "";
1414
1013
  const hasComponent = metadata && Object.keys(metadata).length > 0 && metadata.type;
1415
1014
  const hasTextResponse = textResponse && textResponse.trim().length > 0;
1015
+ const responseParts = [];
1416
1016
  if (hasComponent) {
1417
1017
  const parts = [];
1418
1018
  if (metadata.type) {
@@ -1421,21 +1021,19 @@ var Thread = class {
1421
1021
  if (metadata.name) {
1422
1022
  parts.push(`Name: ${metadata.name}`);
1423
1023
  }
1424
- if (metadata.props?.title) {
1425
- parts.push(`Title: "${metadata.props.title}"`);
1024
+ if (metadata.description) {
1025
+ parts.push(`Description: ${metadata.description}`);
1426
1026
  }
1427
- if (metadata.props?.query) {
1428
- const query = metadata.props.query;
1429
- const truncatedQuery = query.length > 200 ? query.substring(0, 200) + "..." : query;
1430
- parts.push(`Query: ${truncatedQuery}`);
1027
+ if (metadata.props) {
1028
+ parts.push(`Props: ${JSON.stringify(metadata.props)}`);
1431
1029
  }
1432
- if (metadata.props?.config?.components && Array.isArray(metadata.props.config.components)) {
1433
- const componentTypes = metadata.props.config.components.map((c) => c.type).join(", ");
1434
- parts.push(`Multi-component with: ${componentTypes}`);
1435
- }
1436
- assistantResponse = parts.join(", ");
1437
- } else if (hasTextResponse) {
1438
- assistantResponse = textResponse;
1030
+ responseParts.push(parts.join("\n"));
1031
+ }
1032
+ if (hasTextResponse) {
1033
+ responseParts.push(textResponse);
1034
+ }
1035
+ if (responseParts.length > 0) {
1036
+ assistantResponse = responseParts.join("\n");
1439
1037
  } else {
1440
1038
  assistantResponse = "No response generated";
1441
1039
  }
@@ -2060,7 +1658,7 @@ function sendDataResponse3(id, res, sendMessage, clientId) {
2060
1658
  }
2061
1659
 
2062
1660
  // src/userResponse/groq.ts
2063
- var import_dotenv = __toESM(require_main());
1661
+ var import_dotenv = __toESM(require("dotenv"));
2064
1662
 
2065
1663
  // src/userResponse/base-llm.ts
2066
1664
  init_utils();
@@ -2787,18 +2385,16 @@ Your job is to:
2787
2385
  1. **Parse the component suggestions** from the text response (format: 1:component_type : reasoning)
2788
2386
  2. **Match each suggestion with an actual component** from the available list
2789
2387
  3. **Generate proper props** for each matched component to **visualize the analysis results** that were already fetched
2790
- 4. **SELECT the best dashboard layout component** that can accommodate all the matched components
2388
+ 4. **Generate title and description** for the dashboard container
2791
2389
  5. **Generate intelligent follow-up questions (actions)** that the user might naturally ask next based on the data analysis
2792
2390
 
2793
2391
  **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
2392
 
2795
- **APPROACH**: First match all the components suggested in the text response, THEN find the layout that best fits those components.
2796
-
2797
2393
  ## Available Components
2798
2394
 
2799
2395
  {{AVAILABLE_COMPONENTS}}
2800
2396
 
2801
- ## Component Matching Rules (STEP 1)
2397
+ ## Component Matching Rules
2802
2398
  For each component suggestion (c1, c2, c3, etc.) from the text response:
2803
2399
 
2804
2400
  1. **Match by type**: Find components whose \`type\` matches the suggested component type
@@ -2807,23 +2403,10 @@ For each component suggestion (c1, c2, c3, etc.) from the text response:
2807
2403
  - Best fit for the data being visualized
2808
2404
  3. **Fallback**: If no exact type match, find the closest alternative
2809
2405
 
2810
- ## Layout Selection Logic (STEP 2 - After Matching Components)
2811
-
2812
- **After you have matched all components**, select the best dashboard layout:
2813
-
2814
- 1. **Find layout components** by looking for components with \`type: "DashboardLayout"\` in the available components list
2815
- 2. **Read each layout's description** to understand:
2816
- - What structure it provides
2817
- - When it's best used (e.g., comprehensive analysis vs focused analysis)
2818
- - The number and types of components it can accommodate
2819
- 3. **Select the best layout** based on:
2820
- - Which layout can best display ALL the matched components
2821
- - The layout's capacity (how many components it supports)
2822
- - The types of matched components (KPI, charts, tables, etc.)
2823
- - The user question and data complexity
2824
- 4. **If no specific layout fits**, fall back to "MultiComponentContainer" as the default layout
2825
-
2826
- **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.
2406
+ ## Dashboard Container
2407
+ All matched components will be placed in the default **MultiComponentContainer** layout. Your job is to:
2408
+ 1. **Generate a clear title** for the dashboard that summarizes what it shows
2409
+ 2. **Generate a brief description** explaining the dashboard's purpose and scope
2827
2410
 
2828
2411
  ## Props Generation Rules
2829
2412
 
@@ -2937,8 +2520,8 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
2937
2520
 
2938
2521
  \`\`\`json
2939
2522
  {
2940
- "selectedLayoutId": "id_of_the_selected_layout_component",
2941
- "layoutReasoning": "Why this layout was selected based on its description and the analysis needs",
2523
+ "layoutTitle": "Clear, concise title for the overall dashboard/layout (5-10 words)",
2524
+ "layoutDescription": "Brief description of what the dashboard shows and its purpose (1-2 sentences)",
2942
2525
  "matchedComponents": [
2943
2526
  {
2944
2527
  "componentId": "id_from_available_list",
@@ -2968,17 +2551,14 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
2968
2551
  \`\`\`
2969
2552
 
2970
2553
  **CRITICAL:**
2971
- - \`matchedComponents\` MUST include ALL components suggested in the text response (match them first!)
2972
- - \`selectedLayoutId\` MUST be the ID of the selected layout component (must have type "DashboardLayout")
2973
- - \`layoutReasoning\` MUST explain:
2974
- - Why you chose this specific layout component
2975
- - How many components you matched (e.g., "Matched 3 components: 1 KPI, 1 chart, 1 table")
2976
- - Why this layout is the best fit for displaying these specific matched components
2977
- - What makes this layout appropriate for the component types and count
2978
- - The layout selection happens AFTER component matching - don't force components to fit a pre-selected layout
2554
+ - \`matchedComponents\` MUST include ALL components suggested in the text response
2555
+ - \`layoutTitle\` MUST be a clear, concise title (5-10 words) that summarizes what the entire dashboard shows
2556
+ - Examples: "Sales Performance Overview", "Customer Metrics Analysis", "Product Category Breakdown"
2557
+ - \`layoutDescription\` MUST be a brief description (1-2 sentences) explaining the purpose and scope of the dashboard
2558
+ - Should describe what insights the dashboard provides and what data it shows
2979
2559
  - \`actions\` MUST be an array of 4-5 intelligent follow-up questions based on the analysis
2980
2560
  - Return ONLY valid JSON (no markdown code blocks, no text before/after)
2981
- - Generate complete props for each component
2561
+ - Generate complete props for each component including query, title, description, and config
2982
2562
 
2983
2563
 
2984
2564
  `,
@@ -4074,12 +3654,13 @@ var BaseLLM = class {
4074
3654
  /**
4075
3655
  * Match components from text response suggestions and generate follow-up questions
4076
3656
  * Takes a text response with component suggestions (c1:type format) and matches with available components
4077
- * Also generates intelligent follow-up questions (actions) based on the analysis
3657
+ * Also generates title, description, and intelligent follow-up questions (actions) based on the analysis
3658
+ * All components are placed in a default MultiComponentContainer layout
4078
3659
  * @param textResponse - The text response containing component suggestions
4079
3660
  * @param components - List of available components
4080
3661
  * @param apiKey - Optional API key
4081
3662
  * @param logCollector - Optional log collector
4082
- * @returns Object containing matched components, selected layout, reasoning, and follow-up actions
3663
+ * @returns Object containing matched components, layout title/description, and follow-up actions
4083
3664
  */
4084
3665
  async matchComponentsFromTextResponse(textResponse, components, apiKey, logCollector) {
4085
3666
  try {
@@ -4122,24 +3703,17 @@ var BaseLLM = class {
4122
3703
  );
4123
3704
  logger.debug(`[${this.getProviderName()}] Component matching response parsed successfully`);
4124
3705
  const matchedComponents = result.matchedComponents || [];
4125
- const selectedLayoutId = result.selectedLayoutId || "multi-component-container";
4126
- const layoutReasoning = result.layoutReasoning || "No layout reasoning provided";
3706
+ const layoutTitle = result.layoutTitle || "Dashboard";
3707
+ const layoutDescription = result.layoutDescription || "Multi-component dashboard";
4127
3708
  const rawActions = result.actions || [];
4128
3709
  const actions = convertQuestionsToActions(rawActions);
4129
- let selectedLayoutComponent = null;
4130
- if (selectedLayoutId) {
4131
- selectedLayoutComponent = components.find((c) => c.id === selectedLayoutId) || null;
4132
- if (!selectedLayoutComponent) {
4133
- logger.warn(`[${this.getProviderName()}] Layout component ${selectedLayoutId} not found in available components`);
4134
- }
4135
- }
4136
3710
  logger.info(`[${this.getProviderName()}] Matched ${matchedComponents.length} components from text response`);
4137
- logger.info(`[${this.getProviderName()}] Selected layout: (ID: ${selectedLayoutId})`);
4138
- logger.info(`[${this.getProviderName()}] Layout reasoning: ${layoutReasoning}`);
3711
+ logger.info(`[${this.getProviderName()}] Layout title: "${layoutTitle}"`);
3712
+ logger.info(`[${this.getProviderName()}] Layout description: "${layoutDescription}"`);
4139
3713
  logger.info(`[${this.getProviderName()}] Generated ${actions.length} follow-up actions`);
4140
3714
  if (matchedComponents.length > 0) {
4141
- logCollector?.info(`Matched ${matchedComponents.length} components for visualization `);
4142
- logCollector?.info(`Layout reasoning: ${layoutReasoning}`);
3715
+ logCollector?.info(`Matched ${matchedComponents.length} components for visualization`);
3716
+ logCollector?.info(`Dashboard: "${layoutTitle}"`);
4143
3717
  matchedComponents.forEach((comp, idx) => {
4144
3718
  logCollector?.info(` ${idx + 1}. ${comp.componentName} (${comp.componentType}): ${comp.reasoning}`);
4145
3719
  if (comp.props?.query) {
@@ -4173,9 +3747,8 @@ var BaseLLM = class {
4173
3747
  }).filter(Boolean);
4174
3748
  return {
4175
3749
  components: finalComponents,
4176
- selectedLayoutId,
4177
- selectedLayoutComponent,
4178
- layoutReasoning,
3750
+ layoutTitle,
3751
+ layoutDescription,
4179
3752
  actions
4180
3753
  };
4181
3754
  } catch (error) {
@@ -4184,9 +3757,8 @@ var BaseLLM = class {
4184
3757
  logCollector?.error(`Failed to match components: ${errorMsg}`);
4185
3758
  return {
4186
3759
  components: [],
4187
- selectedLayoutId: "",
4188
- selectedLayoutComponent: null,
4189
- layoutReasoning: "Failed to match components due to parsing error",
3760
+ layoutTitle: "Dashboard",
3761
+ layoutDescription: "Failed to generate dashboard",
4190
3762
  actions: []
4191
3763
  };
4192
3764
  }
@@ -4430,9 +4002,12 @@ ${errorMsg}
4430
4002
  textLength: textResponse.length
4431
4003
  }
4432
4004
  );
4005
+ if (wrappedStreamCallback && components && components.length > 0) {
4006
+ wrappedStreamCallback("__TEXT_COMPLETE__COMPONENT_GENERATION_START__");
4007
+ }
4433
4008
  let matchedComponents = [];
4434
- let selectedLayoutComponent = null;
4435
- let layoutReasoning = "No layout selected";
4009
+ let layoutTitle = "Dashboard";
4010
+ let layoutDescription = "Multi-component dashboard";
4436
4011
  let actions = [];
4437
4012
  if (components && components.length > 0) {
4438
4013
  logger.info(`[${this.getProviderName()}] Matching components from text response...`);
@@ -4443,46 +4018,30 @@ ${errorMsg}
4443
4018
  logCollector
4444
4019
  );
4445
4020
  matchedComponents = matchResult.components;
4446
- selectedLayoutComponent = matchResult.selectedLayoutComponent;
4447
- layoutReasoning = matchResult.layoutReasoning;
4021
+ layoutTitle = matchResult.layoutTitle;
4022
+ layoutDescription = matchResult.layoutDescription;
4448
4023
  actions = matchResult.actions;
4449
4024
  }
4450
4025
  let container_componet = null;
4451
4026
  if (matchedComponents.length > 0) {
4452
- if (selectedLayoutComponent) {
4453
- container_componet = {
4454
- ...selectedLayoutComponent,
4455
- id: `${selectedLayoutComponent.id}_${Date.now()}`,
4456
- // Make ID unique for each instance
4457
- props: {
4458
- ...selectedLayoutComponent.props,
4459
- config: {
4460
- ...selectedLayoutComponent.props?.config || {},
4461
- components: matchedComponents
4462
- },
4463
- actions
4464
- }
4465
- };
4466
- logger.info(`[${this.getProviderName()}] Created ${selectedLayoutComponent.name} (${selectedLayoutComponent.type}) container with ${matchedComponents.length} components and ${actions.length} actions`);
4467
- logCollector?.info(`Created ${selectedLayoutComponent.name} with ${matchedComponents.length} components and ${actions.length} actions: ${layoutReasoning}`);
4468
- } else {
4469
- container_componet = {
4470
- id: `multi_container_${Date.now()}`,
4471
- name: "MultiComponentContainer",
4472
- type: "Container",
4473
- description: layoutReasoning,
4474
- category: "dynamic",
4475
- keywords: ["dashboard", "layout", "container"],
4476
- props: {
4477
- config: {
4478
- components: matchedComponents
4479
- },
4480
- actions
4481
- }
4482
- };
4483
- logger.info(`[${this.getProviderName()}] Created fallback MultiComponentContainer with ${matchedComponents.length} components and ${actions.length} actions`);
4484
- logCollector?.info(`Created MultiComponentContainer with ${matchedComponents.length} components and ${actions.length} actions: ${layoutReasoning}`);
4485
- }
4027
+ container_componet = {
4028
+ id: `multi_container_${Date.now()}`,
4029
+ name: "MultiComponentContainer",
4030
+ type: "Container",
4031
+ description: layoutDescription,
4032
+ category: "dynamic",
4033
+ keywords: ["dashboard", "layout", "container"],
4034
+ props: {
4035
+ config: {
4036
+ components: matchedComponents,
4037
+ title: layoutTitle,
4038
+ description: layoutDescription
4039
+ },
4040
+ actions
4041
+ }
4042
+ };
4043
+ logger.info(`[${this.getProviderName()}] Created MultiComponentContainer: "${layoutTitle}" with ${matchedComponents.length} components and ${actions.length} actions`);
4044
+ logCollector?.info(`Created dashboard: "${layoutTitle}" with ${matchedComponents.length} components and ${actions.length} actions`);
4486
4045
  }
4487
4046
  return {
4488
4047
  success: true,
@@ -4490,7 +4049,6 @@ ${errorMsg}
4490
4049
  text: textResponse,
4491
4050
  matchedComponents,
4492
4051
  component: container_componet,
4493
- layoutReasoning,
4494
4052
  actions,
4495
4053
  method: `${this.getProviderName()}-text-response`
4496
4054
  },
@@ -4822,7 +4380,7 @@ var GroqLLM = class extends BaseLLM {
4822
4380
  var groqLLM = new GroqLLM();
4823
4381
 
4824
4382
  // src/userResponse/anthropic.ts
4825
- var import_dotenv2 = __toESM(require_main());
4383
+ var import_dotenv2 = __toESM(require("dotenv"));
4826
4384
  import_dotenv2.default.config();
4827
4385
  var AnthropicLLM = class extends BaseLLM {
4828
4386
  constructor(config) {
@@ -4841,7 +4399,7 @@ var AnthropicLLM = class extends BaseLLM {
4841
4399
  var anthropicLLM = new AnthropicLLM();
4842
4400
 
4843
4401
  // src/userResponse/index.ts
4844
- var import_dotenv3 = __toESM(require_main());
4402
+ var import_dotenv3 = __toESM(require("dotenv"));
4845
4403
  import_dotenv3.default.config();
4846
4404
  function getLLMProviders() {
4847
4405
  const envProviders = process.env.LLM_PROVIDERS;
@@ -5156,7 +4714,7 @@ var CONTEXT_CONFIG = {
5156
4714
  * Set to 0 to disable conversation history
5157
4715
  * Higher values provide more context but may increase token usage
5158
4716
  */
5159
- MAX_CONVERSATION_CONTEXT_BLOCKS: 2
4717
+ MAX_CONVERSATION_CONTEXT_BLOCKS: 3
5160
4718
  };
5161
4719
 
5162
4720
  // src/handlers/user-prompt-request.ts