@superatomai/sdk-node 0.0.72 → 0.0.74

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
@@ -3310,24 +3310,20 @@ If adaptation is not possible or would fundamentally change the component:
3310
3310
  "dash-comp-picker": {
3311
3311
  system: `You are a component selection expert that picks the best dashboard component and generates complete props based on user requests.
3312
3312
 
3313
+ ## CRITICAL - READ FIRST
3314
+
3315
+ 1. Your ENTIRE response must be ONLY a raw JSON object - start with { end with }
3316
+ 2. DO NOT explain or answer the user's question in natural language
3317
+ 3. DO NOT use markdown code blocks (no \`\`\`)
3318
+ 4. DO NOT add any text before or after the JSON
3319
+ 5. After executing tools (if needed), return JSON with component selection - NOT a text summary of results
3320
+
3313
3321
  ## Your Task
3314
3322
 
3315
3323
  Analyze the user's request and:
3316
3324
  1. **Select the most appropriate component** from the available components list
3317
- 2. **Determine the data source**: Database query OR External tool
3318
- 3. **Generate complete props** for the selected component
3319
-
3320
- ## Available External Tools
3321
-
3322
- The following external tools are available:
3323
-
3324
- {{AVAILABLE_TOOLS}}
3325
-
3326
- When a tool is needed to complete the user's request:
3327
- 1. **Analyze the request** to determine which tool is needed
3328
- 2. **Extract parameters** from the user's question
3329
- 3. **Execute the tool** by calling it with the extracted parameters
3330
- 4. **Use the results** to configure the component (field names for axes, columns, etc.)
3325
+ 2. **Determine the data source**: Database query OR External tool (ERP)
3326
+ 3. **Generate complete props** for the selected component including the data retrieval/modification method
3331
3327
 
3332
3328
  ## Component Selection Rules
3333
3329
 
@@ -3357,7 +3353,7 @@ The user prompt may contain an **existing component** to update. Detect this by
3357
3353
 
3358
3354
  ### Use DATABASE when:
3359
3355
  - User asks about data that exists in the database schema
3360
- - Questions about internal business data
3356
+ - Questions about internal business data
3361
3357
  - CRUD operations on database tables
3362
3358
 
3363
3359
  ### Use EXTERNAL TOOL when:
@@ -3370,6 +3366,12 @@ The user prompt may contain an **existing component** to update. Detect this by
3370
3366
 
3371
3367
  **CRITICAL**: Look at each component's "Props Structure" in the available components list. Generate ALL props that the component expects.
3372
3368
 
3369
+ **CRITICAL: Each component uses EXACTLY ONE data source - never both!**
3370
+ - If using \`query\`, set \`externalTool: null\`
3371
+ - If using \`externalTool\`, set \`query: null\`
3372
+ - NEVER copy placeholder/description text from component metadata as actual values
3373
+ - \`externalTool.parameters\` MUST be an object, never a string
3374
+
3373
3375
  ### For Data Viewing Components (charts, tables, KPIs):
3374
3376
 
3375
3377
  **Option A: Database Query** (when data is in database)
@@ -3378,21 +3380,19 @@ The user prompt may contain an **existing component** to update. Detect this by
3378
3380
  "query": {
3379
3381
  "sql": "SELECT column1, column2 FROM table WHERE condition = $param LIMIT 32",
3380
3382
  "params": { "param": "value" }
3381
- }
3383
+ },
3384
+ "externalTool": null
3382
3385
  }
3383
3386
  \`\`\`
3384
3387
 
3385
3388
  **Option B: External Tool** (when data is from ERP/external system)
3386
3389
  \`\`\`json
3387
3390
  {
3391
+ "query": null,
3388
3392
  "externalTool": {
3389
3393
  "toolId": "tool_id_from_list",
3390
3394
  "toolName": "Tool Display Name",
3391
- "action": "get",
3392
- "params": {
3393
- "param1": "value1",
3394
- "param2": "value2"
3395
- }
3395
+ "parameters": { "param1": "value1", "param2": "value2" }
3396
3396
  }
3397
3397
  }
3398
3398
  \`\`\`
@@ -3406,6 +3406,7 @@ The user prompt may contain an **existing component** to update. Detect this by
3406
3406
  "sql": "INSERT INTO table (col1, col2) VALUES ($col1, $col2)",
3407
3407
  "params": {}
3408
3408
  },
3409
+ "externalTool": null,
3409
3410
  "fields": [
3410
3411
  { "name": "col1", "type": "text", "required": true },
3411
3412
  { "name": "col2", "type": "number", "required": false }
@@ -3413,16 +3414,38 @@ The user prompt may contain an **existing component** to update. Detect this by
3413
3414
  }
3414
3415
  \`\`\`
3415
3416
 
3417
+ For UPDATE:
3418
+ \`\`\`json
3419
+ {
3420
+ "query": {
3421
+ "sql": "UPDATE table SET col1 = $col1, col2 = $col2 WHERE id = $id",
3422
+ "params": { "id": "record_id" }
3423
+ },
3424
+ "externalTool": null
3425
+ }
3426
+ \`\`\`
3427
+
3428
+ For DELETE:
3429
+ \`\`\`json
3430
+ {
3431
+ "query": {
3432
+ "sql": "DELETE FROM table WHERE id = $id",
3433
+ "params": { "id": "record_id" }
3434
+ },
3435
+ "externalTool": null,
3436
+ "submitButtonText": "Confirm Delete",
3437
+ "submitButtonColor": "danger"
3438
+ }
3439
+ \`\`\`
3440
+
3416
3441
  **Option B: External Tool Mutation**
3417
3442
  \`\`\`json
3418
3443
  {
3444
+ "query": null,
3419
3445
  "externalTool": {
3420
3446
  "toolId": "tool_id_from_list",
3421
3447
  "toolName": "Tool Display Name",
3422
- "action": "create|update|delete",
3423
- "params": {
3424
- "param1": "value_or_placeholder"
3425
- }
3448
+ "parameters": { "param1": "value_or_placeholder" }
3426
3449
  },
3427
3450
  "fields": [
3428
3451
  { "name": "param1", "type": "text", "required": true }
@@ -3437,6 +3460,7 @@ The user prompt may contain an **existing component** to update. Detect this by
3437
3460
 
3438
3461
  You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
3439
3462
 
3463
+ \`\`\`json
3440
3464
  {
3441
3465
  "componentId": "id_from_available_list_or_existing_component_id",
3442
3466
  "componentName": "name_of_component",
@@ -3451,6 +3475,7 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
3451
3475
  // Include all other required props (title, description, config, fields, etc.)
3452
3476
  }
3453
3477
  }
3478
+ \`\`\`
3454
3479
 
3455
3480
  **CRITICAL:**
3456
3481
  - Return ONLY valid JSON (no markdown code blocks, no text before/after)
@@ -3473,7 +3498,8 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
3473
3498
 
3474
3499
  ---
3475
3500
 
3476
- ## CONTEXT`,
3501
+ ## CONTEXT
3502
+ `,
3477
3503
  user: `{{USER_PROMPT}}`
3478
3504
  },
3479
3505
  "dash-filter-picker": {
@@ -3619,9 +3645,7 @@ var PromptLoader = class {
3619
3645
  this.databaseRulesCache = /* @__PURE__ */ new Map();
3620
3646
  this.isInitialized = false;
3621
3647
  this.databaseType = "postgresql";
3622
- logger.debug("Initializing PromptLoader...");
3623
3648
  this.promptsDir = config?.promptsDir || path2.join(process.cwd(), ".prompts");
3624
- logger.debug(`Prompts directory set to: ${this.promptsDir}`);
3625
3649
  }
3626
3650
  /**
3627
3651
  * Load a prompt template from file system OR fallback to hardcoded prompts
@@ -3635,7 +3659,6 @@ var PromptLoader = class {
3635
3659
  if (fs3.existsSync(systemPath) && fs3.existsSync(userPath)) {
3636
3660
  const system = fs3.readFileSync(systemPath, "utf-8");
3637
3661
  const user = fs3.readFileSync(userPath, "utf-8");
3638
- logger.info(`\u2713 Loaded prompt '${promptName}' from file system: ${this.promptsDir}`);
3639
3662
  return { system, user };
3640
3663
  }
3641
3664
  } catch (error) {
@@ -3643,7 +3666,6 @@ var PromptLoader = class {
3643
3666
  }
3644
3667
  const hardcodedPrompt = PROMPTS[promptName];
3645
3668
  if (hardcodedPrompt) {
3646
- logger.info(`\u2713 Loaded prompt '${promptName}' from hardcoded fallback`);
3647
3669
  return hardcodedPrompt;
3648
3670
  }
3649
3671
  throw new Error(`Prompt template '${promptName}' not found in either ${this.promptsDir} or hardcoded prompts. Available prompts: ${Object.keys(PROMPTS).join(", ")}`);
@@ -3657,7 +3679,6 @@ var PromptLoader = class {
3657
3679
  logger.debug("PromptLoader already initialized, skipping...");
3658
3680
  return;
3659
3681
  }
3660
- logger.info("Loading prompts into memory...");
3661
3682
  const promptTypes = Object.keys(PROMPTS);
3662
3683
  for (const promptName of promptTypes) {
3663
3684
  try {
@@ -3669,7 +3690,6 @@ var PromptLoader = class {
3669
3690
  }
3670
3691
  }
3671
3692
  this.isInitialized = true;
3672
- logger.info(`Successfully loaded ${this.promptCache.size} prompt templates into memory`);
3673
3693
  }
3674
3694
  /**
3675
3695
  * Replace variables in a template string using {{VARIABLE_NAME}} pattern
@@ -3709,7 +3729,6 @@ var PromptLoader = class {
3709
3729
  const processedContext = this.replaceVariables(contextMarker + contextPart, variables);
3710
3730
  const staticLength = processedStatic.length;
3711
3731
  const contextLength = processedContext.length;
3712
- logger.debug(`\u2713 Prompt caching enabled for '${promptName}' (cached: ${staticLength} chars, dynamic: ${contextLength} chars)`);
3713
3732
  return {
3714
3733
  system: [
3715
3734
  {
@@ -3746,7 +3765,6 @@ var PromptLoader = class {
3746
3765
  this.promptsDir = dir;
3747
3766
  this.isInitialized = false;
3748
3767
  this.promptCache.clear();
3749
- logger.debug(`Prompts directory changed to: ${dir}`);
3750
3768
  }
3751
3769
  /**
3752
3770
  * Get current prompts directory
@@ -3774,7 +3792,6 @@ var PromptLoader = class {
3774
3792
  setDatabaseType(type) {
3775
3793
  this.databaseType = type;
3776
3794
  this.databaseRulesCache.clear();
3777
- logger.debug(`Database type set to: ${type}`);
3778
3795
  }
3779
3796
  /**
3780
3797
  * Get current database type
@@ -3790,7 +3807,6 @@ var PromptLoader = class {
3790
3807
  */
3791
3808
  async loadDatabaseRules() {
3792
3809
  if (this.databaseRulesCache.has(this.databaseType)) {
3793
- logger.debug(`\u2713 Database rules for '${this.databaseType}' loaded from cache`);
3794
3810
  return this.databaseRulesCache.get(this.databaseType);
3795
3811
  }
3796
3812
  const rulesPath = path2.join(this.promptsDir, "database-rules", `${this.databaseType}.md`);
@@ -3798,7 +3814,6 @@ var PromptLoader = class {
3798
3814
  if (fs3.existsSync(rulesPath)) {
3799
3815
  const rules = fs3.readFileSync(rulesPath, "utf-8");
3800
3816
  this.databaseRulesCache.set(this.databaseType, rules);
3801
- logger.info(`\u2713 Loaded database rules for '${this.databaseType}' from ${rulesPath}`);
3802
3817
  return rules;
3803
3818
  }
3804
3819
  } catch (error) {
@@ -4074,7 +4089,6 @@ var Schema = class {
4074
4089
  * @returns Parsed schema object or null if error occurs
4075
4090
  */
4076
4091
  getDatabaseSchema() {
4077
- logger.info(`SCHEMA_FILE_PATH: ${this.schemaFilePath}`);
4078
4092
  try {
4079
4093
  const dir = path3.dirname(this.schemaFilePath);
4080
4094
  if (!fs4.existsSync(dir)) {
@@ -4343,14 +4357,6 @@ Format: [TIMESTAMP] [REQUEST_ID] [PROVIDER/MODEL] [METHOD]
4343
4357
  Cost: $${entry.costUSD.toFixed(6)} | Time: ${entry.durationMs}ms${toolInfo}${errorInfo}${cacheStatus}
4344
4358
  `;
4345
4359
  this.logStream?.write(logLine);
4346
- if (entry.cacheReadTokens && entry.cacheReadTokens > 0) {
4347
- console.log(`[LLM] \u26A1 CACHE HIT: ${entry.cacheReadTokens.toLocaleString()} tokens read from cache (${entry.method})`);
4348
- } else if (entry.cacheWriteTokens && entry.cacheWriteTokens > 0) {
4349
- console.log(`[LLM] \u{1F4DD} CACHE WRITE: ${entry.cacheWriteTokens.toLocaleString()} tokens cached for future requests (${entry.method})`);
4350
- }
4351
- if (process.env.SUPERATOM_LOG_LEVEL === "verbose") {
4352
- console.log("\n[LLM-Usage]", logLine);
4353
- }
4354
4360
  }
4355
4361
  /**
4356
4362
  * Log session summary (call at end of request)
@@ -4383,11 +4389,6 @@ Avg Time/Call: ${Math.round(this.sessionStats.totalDurationMs / this.sessionStat
4383
4389
 
4384
4390
  `;
4385
4391
  this.logStream?.write(summary);
4386
- console.log("\n[LLM-Usage] Session Summary:");
4387
- console.log(` Calls: ${this.sessionStats.totalCalls} | Tokens: ${(this.sessionStats.totalInputTokens + this.sessionStats.totalOutputTokens).toLocaleString()} | Cost: $${this.sessionStats.totalCostUSD.toFixed(4)} | Time: ${(this.sessionStats.totalDurationMs / 1e3).toFixed(2)}s`);
4388
- if (hasCaching) {
4389
- console.log(` Cache: ${this.sessionStats.totalCacheReadTokens.toLocaleString()} read, ${this.sessionStats.totalCacheWriteTokens.toLocaleString()} written | Savings: ~$${cacheReadSavings.toFixed(4)}`);
4390
- }
4391
4392
  }
4392
4393
  /**
4393
4394
  * Reset session stats (call at start of new user request)
@@ -4428,7 +4429,6 @@ Format: [TIMESTAMP] [REQUEST_ID] [PROVIDER/MODEL] [METHOD]
4428
4429
  `;
4429
4430
  this.logStream.write(header);
4430
4431
  this.resetSession();
4431
- console.log(`[LLM-Usage] Log file reset for new request: ${this.logPath}`);
4432
4432
  } catch (error) {
4433
4433
  console.error("[LLM-Usage-Logger] Failed to reset log file:", error);
4434
4434
  }
@@ -5902,21 +5902,20 @@ var getKnowledgeBase = async ({
5902
5902
  }) => {
5903
5903
  try {
5904
5904
  if (!collections || !collections["knowledge-base"] || !collections["knowledge-base"]["query"]) {
5905
- logger.info("[KnowledgeBase] knowledge-base.query collection not registered, skipping");
5905
+ logger.warn("[KnowledgeBase] knowledge-base.query collection not registered, skipping");
5906
5906
  return "";
5907
5907
  }
5908
- logger.info(`[KnowledgeBase] Querying knowledge base for: "${prompt.substring(0, 50)}..."`);
5909
5908
  const result = await collections["knowledge-base"]["query"]({
5910
5909
  prompt,
5911
5910
  topK
5912
5911
  });
5913
5912
  if (!result || !result.content) {
5914
- logger.info("[KnowledgeBase] No knowledge base results returned");
5913
+ logger.warn("[KnowledgeBase] No knowledge base results returned");
5915
5914
  return "";
5916
5915
  }
5917
5916
  logger.info(`[KnowledgeBase] Retrieved knowledge base context (${result.content.length} chars)`);
5918
5917
  if (result.metadata?.sources && result.metadata.sources.length > 0) {
5919
- logger.debug(`[KnowledgeBase] Sources: ${result.metadata.sources.map((s) => s.title).join(", ")}`);
5918
+ logger.warn(`[KnowledgeBase] Sources: ${result.metadata.sources.map((s) => s.title).join(", ")}`);
5920
5919
  }
5921
5920
  return result.content;
5922
5921
  } catch (error) {
@@ -5931,13 +5930,12 @@ var getGlobalKnowledgeBase = async ({
5931
5930
  }) => {
5932
5931
  try {
5933
5932
  if (!collections || !collections["knowledge-base"] || !collections["knowledge-base"]["getGlobal"]) {
5934
- logger.info("[KnowledgeBase] knowledge-base.getGlobal collection not registered, skipping");
5933
+ logger.warn("[KnowledgeBase] knowledge-base.getGlobal collection not registered, skipping");
5935
5934
  return "";
5936
5935
  }
5937
- logger.info("[KnowledgeBase] Fetching global knowledge base nodes...");
5938
5936
  const result = await collections["knowledge-base"]["getGlobal"]({ limit });
5939
5937
  if (!result || !result.content) {
5940
- logger.info("[KnowledgeBase] No global knowledge base nodes found");
5938
+ logger.warn("[KnowledgeBase] No global knowledge base nodes found");
5941
5939
  return "";
5942
5940
  }
5943
5941
  logger.info(`[KnowledgeBase] Retrieved ${result.count || 0} global knowledge base nodes`);
@@ -5955,14 +5953,13 @@ var getUserKnowledgeBase = async ({
5955
5953
  }) => {
5956
5954
  try {
5957
5955
  if (!userId) {
5958
- logger.info("[KnowledgeBase] No userId provided, skipping user knowledge base");
5956
+ logger.warn("[KnowledgeBase] No userId provided, skipping user knowledge base");
5959
5957
  return "";
5960
5958
  }
5961
5959
  if (!collections || !collections["knowledge-base"] || !collections["knowledge-base"]["getByUser"]) {
5962
- logger.info("[KnowledgeBase] knowledge-base.getByUser collection not registered, skipping");
5960
+ logger.warn("[KnowledgeBase] knowledge-base.getByUser collection not registered, skipping");
5963
5961
  return "";
5964
5962
  }
5965
- logger.info(`[KnowledgeBase] Fetching user knowledge base nodes for userId: ${userId}...`);
5966
5963
  const result = await collections["knowledge-base"]["getByUser"]({
5967
5964
  userId: Number(userId),
5968
5965
  limit
@@ -5985,7 +5982,6 @@ var getAllKnowledgeBase = async ({
5985
5982
  userId,
5986
5983
  topK = 3
5987
5984
  }) => {
5988
- logger.info("[KnowledgeBase] Fetching all knowledge base contexts...");
5989
5985
  const [globalContext, userContext, queryContext] = await Promise.all([
5990
5986
  getGlobalKnowledgeBase({ collections }),
5991
5987
  getUserKnowledgeBase({ collections, userId }),
@@ -6007,7 +6003,6 @@ var getAllKnowledgeBase = async ({
6007
6003
  combinedContext += "The following information is semantically relevant to the current query:\n\n";
6008
6004
  combinedContext += queryContext + "\n\n";
6009
6005
  }
6010
- logger.info(`[KnowledgeBase] Combined knowledge base context: global=${globalContext.length} chars, user=${userContext.length} chars, query=${queryContext.length} chars`);
6011
6006
  return {
6012
6007
  globalContext,
6013
6008
  userContext,
@@ -6244,11 +6239,11 @@ var searchConversationsWithReranking = async (options) => {
6244
6239
  } = options;
6245
6240
  try {
6246
6241
  if (!collections || !collections["conversation-history"]) {
6247
- logger.info("[ConversationSearch] conversation-history collection not registered, skipping");
6242
+ logger.warn("[ConversationSearch] conversation-history collection not registered, skipping");
6248
6243
  return null;
6249
6244
  }
6250
6245
  if (!collections["conversation-history"]["searchMultiple"]) {
6251
- logger.info("[ConversationSearch] searchMultiple not available, falling back to standard search");
6246
+ logger.warn("[ConversationSearch] searchMultiple not available, falling back to standard search");
6252
6247
  return searchConversations({
6253
6248
  userPrompt,
6254
6249
  collections,
@@ -6256,9 +6251,6 @@ var searchConversationsWithReranking = async (options) => {
6256
6251
  similarityThreshold
6257
6252
  });
6258
6253
  }
6259
- logger.info(`[ConversationSearch] Hybrid search for: "${userPrompt.substring(0, 50)}..."`);
6260
- logger.info(`[ConversationSearch] Fetching ${rerankCandidates} candidates for reranking`);
6261
- logger.info(`[ConversationSearch] Weights - Semantic: ${hybridOptions.semanticWeight}, BM25: ${hybridOptions.bm25Weight}`);
6262
6254
  const results = await collections["conversation-history"]["searchMultiple"]({
6263
6255
  userPrompt,
6264
6256
  userId,
@@ -6299,7 +6291,6 @@ var searchConversationsWithReranking = async (options) => {
6299
6291
  logger.info(
6300
6292
  `[ConversationSearch] \u2713 Found match with semantic score ${(semanticScore * 100).toFixed(2)}%`
6301
6293
  );
6302
- logger.info(` - Returning cached result for: "${matchedUserPrompt}"`);
6303
6294
  return {
6304
6295
  uiBlock: best.uiBlock,
6305
6296
  similarity: semanticScore,
@@ -6741,10 +6732,9 @@ Fixed SQL query:`;
6741
6732
  * @param component - The component to validate
6742
6733
  * @param collections - Collections object containing database execute function
6743
6734
  * @param apiKey - Optional API key for LLM calls
6744
- * @param logCollector - Optional log collector for logging
6745
6735
  * @returns Validation result with component, query key, and result
6746
6736
  */
6747
- async validateSingleQuery(component, collections, apiKey, logCollector) {
6737
+ async validateSingleQuery(component, collections, apiKey) {
6748
6738
  const query = component.props?.query;
6749
6739
  const originalQueryKey = this.getQueryCacheKey(query);
6750
6740
  const queryStr = typeof query === "string" ? query : query?.sql || "";
@@ -6765,7 +6755,6 @@ Fixed SQL query:`;
6765
6755
  validated = true;
6766
6756
  queryCache.set(validationResult.cacheKey, result);
6767
6757
  logger.info(`[${this.config.providerName}] \u2713 Query validated for ${component.name} (attempt ${attempts}) - cached for frontend`);
6768
- logCollector?.info(`\u2713 Query validated for ${component.name}`);
6769
6758
  if (currentQueryStr !== queryStr) {
6770
6759
  const fixedQuery = typeof query === "string" ? currentQueryStr : { ...query, sql: currentQueryStr };
6771
6760
  component.props = {
@@ -6778,14 +6767,11 @@ Fixed SQL query:`;
6778
6767
  } catch (error) {
6779
6768
  lastError = error instanceof Error ? error.message : String(error);
6780
6769
  logger.warn(`[${this.config.providerName}] Query validation failed for ${component.name} (attempt ${attempts}/${MAX_QUERY_VALIDATION_RETRIES}): ${lastError}`);
6781
- logCollector?.warn(`Query validation failed for ${component.name}: ${lastError}`);
6782
6770
  if (attempts >= MAX_QUERY_VALIDATION_RETRIES) {
6783
6771
  logger.error(`[${this.config.providerName}] \u2717 Max retries reached for ${component.name}, excluding from response`);
6784
- logCollector?.error(`Max retries reached for ${component.name}, component excluded from response`);
6785
6772
  break;
6786
6773
  }
6787
6774
  logger.info(`[${this.config.providerName}] Requesting query fix from LLM for ${component.name}...`);
6788
- logCollector?.info(`Requesting query fix for ${component.name}...`);
6789
6775
  try {
6790
6776
  const fixedQueryStr = await this.requestQueryFix(
6791
6777
  currentQueryStr,
@@ -6819,7 +6805,6 @@ Fixed SQL query:`;
6819
6805
  }
6820
6806
  if (!validated) {
6821
6807
  logger.warn(`[${this.config.providerName}] Component ${component.name} excluded from response due to failed query validation`);
6822
- logCollector?.warn(`Component ${component.name} excluded from response`);
6823
6808
  }
6824
6809
  return {
6825
6810
  component: validated ? component : null,
@@ -6833,10 +6818,9 @@ Fixed SQL query:`;
6833
6818
  * @param components - Array of components with potential queries
6834
6819
  * @param collections - Collections object containing database execute function
6835
6820
  * @param apiKey - Optional API key for LLM calls
6836
- * @param logCollector - Optional log collector for logging
6837
6821
  * @returns Object with validated components and query results map
6838
6822
  */
6839
- async validateComponentQueries(components, collections, apiKey, logCollector) {
6823
+ async validateComponentQueries(components, collections, apiKey) {
6840
6824
  const queryResults = /* @__PURE__ */ new Map();
6841
6825
  const validatedComponents = [];
6842
6826
  const componentsWithoutQuery = [];
@@ -6853,9 +6837,8 @@ Fixed SQL query:`;
6853
6837
  return { components: validatedComponents, queryResults };
6854
6838
  }
6855
6839
  logger.info(`[${this.config.providerName}] Validating ${componentsWithQuery.length} component queries in parallel...`);
6856
- logCollector?.info(`Validating ${componentsWithQuery.length} component queries in parallel...`);
6857
6840
  const validationPromises = componentsWithQuery.map(
6858
- (component) => this.validateSingleQuery(component, collections, apiKey, logCollector)
6841
+ (component) => this.validateSingleQuery(component, collections, apiKey)
6859
6842
  );
6860
6843
  const results = await Promise.allSettled(validationPromises);
6861
6844
  for (let i = 0; i < results.length; i++) {
@@ -6872,7 +6855,6 @@ Fixed SQL query:`;
6872
6855
  }
6873
6856
  } else {
6874
6857
  logger.error(`[${this.config.providerName}] Unexpected error validating ${component.name}: ${result.reason}`);
6875
- logCollector?.error(`Unexpected error validating ${component.name}: ${result.reason}`);
6876
6858
  }
6877
6859
  }
6878
6860
  logger.info(`[${this.config.providerName}] Parallel validation complete: ${validatedComponents.length}/${components.length} components validated`);
@@ -6934,22 +6916,17 @@ var ToolExecutorService = class {
6934
6916
  let sql = toolInput.sql;
6935
6917
  const params = toolInput.params || {};
6936
6918
  const reasoning = toolInput.reasoning;
6937
- const { streamBuffer, collections, logCollector, providerName } = this.config;
6919
+ const { streamBuffer, collections, providerName } = this.config;
6938
6920
  sql = ensureQueryLimit(sql, MAX_COMPONENT_QUERY_LIMIT, MAX_COMPONENT_QUERY_LIMIT);
6939
6921
  const queryKey = sql.toLowerCase().replace(/\s+/g, " ").trim();
6940
6922
  const attempts = (this.queryAttempts.get(queryKey) || 0) + 1;
6941
6923
  this.queryAttempts.set(queryKey, attempts);
6942
- logger.info(`[${providerName}] Executing query (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${sql.substring(0, 100)}...`);
6943
6924
  if (Object.keys(params).length > 0) {
6944
6925
  logger.info(`[${providerName}] Query params: ${JSON.stringify(params)}`);
6945
6926
  }
6946
- if (reasoning) {
6947
- logCollector?.info(`Query reasoning: ${reasoning}`);
6948
- }
6949
6927
  if (attempts > MAX_QUERY_ATTEMPTS) {
6950
6928
  const errorMsg = `Maximum query attempts (${MAX_QUERY_ATTEMPTS}) reached. Unable to generate a valid query for your question.`;
6951
6929
  logger.error(`[${providerName}] ${errorMsg}`);
6952
- logCollector?.error(errorMsg);
6953
6930
  this.maxAttemptsReached = true;
6954
6931
  if (streamBuffer.hasCallback()) {
6955
6932
  streamBuffer.write(`
@@ -7009,11 +6986,6 @@ ${sql}
7009
6986
  await streamDelay();
7010
6987
  }
7011
6988
  }
7012
- logCollector?.logQuery?.(
7013
- `Executing SQL query (attempt ${attempts})`,
7014
- { sql, params },
7015
- { reasoning, attempt: attempts }
7016
- );
7017
6989
  if (!collections?.["database"]?.["execute"]) {
7018
6990
  throw new Error("Database collection not registered. Please register database.execute collection to execute queries.");
7019
6991
  }
@@ -7025,8 +6997,6 @@ ${sql}
7025
6997
  );
7026
6998
  const data = result?.data || result;
7027
6999
  const rowCount = result?.count ?? (Array.isArray(data) ? data.length : "N/A");
7028
- logger.info(`[${providerName}] Query executed successfully, rows returned: ${rowCount}`);
7029
- logCollector?.info(`Query successful, returned ${rowCount} rows`);
7030
7000
  if (streamBuffer.hasCallback()) {
7031
7001
  streamBuffer.write(`
7032
7002
  \u2705 **Query executed successfully!**
@@ -7075,7 +7045,6 @@ ${sql}
7075
7045
  maxRows: DEFAULT_MAX_ROWS_FOR_LLM,
7076
7046
  maxCharsPerField: DEFAULT_MAX_CHARS_PER_FIELD2
7077
7047
  });
7078
- logger.info(`[${providerName}] Query result formatted: ${formattedResult.summary.recordsShown}/${formattedResult.summary.totalRecords} records`);
7079
7048
  if (formattedResult.truncationNote) {
7080
7049
  logger.info(`[${providerName}] Truncation: ${formattedResult.truncationNote}`);
7081
7050
  }
@@ -7083,7 +7052,6 @@ ${sql}
7083
7052
  } catch (error) {
7084
7053
  const errorMsg = error instanceof Error ? error.message : String(error);
7085
7054
  logger.error(`[${providerName}] Query execution failed (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${errorMsg}`);
7086
- logCollector?.error(`Query failed (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${errorMsg}`);
7087
7055
  userPromptErrorLogger.logSqlError(sql, error instanceof Error ? error : new Error(errorMsg), Object.keys(params).length > 0 ? Object.values(params) : void 0);
7088
7056
  if (streamBuffer.hasCallback()) {
7089
7057
  streamBuffer.write(`\u274C **Query execution failed:**
@@ -7105,19 +7073,16 @@ ${errorMsg}
7105
7073
  * Execute an external tool with retry tracking and streaming feedback
7106
7074
  */
7107
7075
  async executeExternalTool(toolName, toolInput, externalTools) {
7108
- const { streamBuffer, logCollector, providerName } = this.config;
7076
+ const { streamBuffer, providerName } = this.config;
7109
7077
  const externalTool = externalTools?.find((t) => t.id === toolName);
7110
7078
  if (!externalTool) {
7111
7079
  throw new Error(`Unknown tool: ${toolName}`);
7112
7080
  }
7113
7081
  const attempts = (this.toolAttempts.get(toolName) || 0) + 1;
7114
7082
  this.toolAttempts.set(toolName, attempts);
7115
- logger.info(`[${providerName}] Executing external tool: ${externalTool.name} (attempt ${attempts}/${MAX_TOOL_ATTEMPTS})`);
7116
- logCollector?.info(`Executing external tool: ${externalTool.name} (attempt ${attempts}/${MAX_TOOL_ATTEMPTS})...`);
7117
7083
  if (attempts > MAX_TOOL_ATTEMPTS) {
7118
7084
  const errorMsg = `Maximum attempts (${MAX_TOOL_ATTEMPTS}) reached for tool: ${externalTool.name}`;
7119
7085
  logger.error(`[${providerName}] ${errorMsg}`);
7120
- logCollector?.error(errorMsg);
7121
7086
  if (streamBuffer.hasCallback()) {
7122
7087
  streamBuffer.write(`
7123
7088
 
@@ -7152,8 +7117,6 @@ Please try rephrasing your request or contact support.
7152
7117
  `Running ${externalTool.name}`,
7153
7118
  streamBuffer
7154
7119
  );
7155
- logger.info(`[${providerName}] External tool ${externalTool.name} executed successfully`);
7156
- logCollector?.info(`\u2713 ${externalTool.name} executed successfully`);
7157
7120
  if (!this.executedToolsList.find((t) => t.id === externalTool.id)) {
7158
7121
  const formattedForTracking = formatToolResultForLLM(result, {
7159
7122
  toolName: externalTool.name,
@@ -7173,7 +7136,6 @@ Please try rephrasing your request or contact support.
7173
7136
  },
7174
7137
  outputSchema: externalTool.outputSchema
7175
7138
  });
7176
- logger.info(`[${providerName}] Tracked executed tool: ${externalTool.name} with ${formattedForTracking.summary.totalRecords} total records`);
7177
7139
  }
7178
7140
  if (streamBuffer.hasCallback()) {
7179
7141
  streamBuffer.write(`\u2705 **${externalTool.name} completed successfully**
@@ -7187,7 +7149,6 @@ Please try rephrasing your request or contact support.
7187
7149
  maxRows: DEFAULT_MAX_ROWS_FOR_LLM,
7188
7150
  maxCharsPerField: DEFAULT_MAX_CHARS_PER_FIELD2
7189
7151
  });
7190
- logger.info(`[${providerName}] Tool result formatted: ${formattedToolResult.summary.recordsShown}/${formattedToolResult.summary.totalRecords} records`);
7191
7152
  if (formattedToolResult.truncationNote) {
7192
7153
  logger.info(`[${providerName}] Truncation: ${formattedToolResult.truncationNote}`);
7193
7154
  }
@@ -7195,7 +7156,6 @@ Please try rephrasing your request or contact support.
7195
7156
  } catch (error) {
7196
7157
  const errorMsg = error instanceof Error ? error.message : String(error);
7197
7158
  logger.error(`[${providerName}] External tool ${externalTool.name} failed (attempt ${attempts}/${MAX_TOOL_ATTEMPTS}): ${errorMsg}`);
7198
- logCollector?.error(`\u2717 ${externalTool.name} failed: ${errorMsg}`);
7199
7159
  userPromptErrorLogger.logToolError(externalTool.name, toolInput, error instanceof Error ? error : new Error(errorMsg));
7200
7160
  if (streamBuffer.hasCallback()) {
7201
7161
  streamBuffer.write(`\u274C **${externalTool.name} failed:**
@@ -7273,7 +7233,6 @@ var BaseLLM = class {
7273
7233
  return;
7274
7234
  }
7275
7235
  this.conversationSimilarityThreshold = threshold;
7276
- logger.info(`[${this.getProviderName()}] Conversation similarity threshold set to: ${threshold}`);
7277
7236
  }
7278
7237
  /**
7279
7238
  * Get the current conversation similarity threshold
@@ -7316,16 +7275,14 @@ var BaseLLM = class {
7316
7275
  * @param analysisContent - The text response containing component suggestions
7317
7276
  * @param components - List of available components
7318
7277
  * @param apiKey - Optional API key
7319
- * @param logCollector - Optional log collector
7320
7278
  * @param componentStreamCallback - Optional callback to stream primary KPI component as soon as it's identified
7321
7279
  * @returns Object containing matched components, layout title/description, and follow-up actions
7322
7280
  */
7323
- async matchComponentsFromAnalysis(analysisContent, components, userPrompt, apiKey, logCollector, componentStreamCallback, deferredTools, executedTools, collections, userId) {
7281
+ async matchComponentsFromAnalysis(analysisContent, components, userPrompt, apiKey, componentStreamCallback, deferredTools, executedTools, collections, userId) {
7324
7282
  const methodStartTime = Date.now();
7325
7283
  const methodName = "matchComponentsFromAnalysis";
7326
7284
  logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("complex")}`);
7327
7285
  try {
7328
- logger.debug(`[${this.getProviderName()}] Starting component matching from text response`);
7329
7286
  let availableComponentsText = "No components available";
7330
7287
  if (components && components.length > 0) {
7331
7288
  availableComponentsText = components.map((comp, idx) => {
@@ -7341,7 +7298,6 @@ var BaseLLM = class {
7341
7298
  }
7342
7299
  let deferredToolsText = "No deferred external tools for this request.";
7343
7300
  if (deferredTools && deferredTools.length > 0) {
7344
- logger.info(`[${this.getProviderName()}] Passing ${deferredTools.length} deferred tools to component matching`);
7345
7301
  deferredToolsText = "The following external tools need user input via a Form component.\n**IMPORTANT: Use these EXACT values when generating Form externalTool prop.**\n\n" + deferredTools.map((tool, idx) => {
7346
7302
  return `${idx + 1}. **${tool.name}**
7347
7303
  toolId: "${tool.id}" (USE THIS EXACT VALUE - do not modify!)
@@ -7353,7 +7309,6 @@ var BaseLLM = class {
7353
7309
  }
7354
7310
  let executedToolsText = "No external tools were executed for data fetching.";
7355
7311
  if (executedTools && executedTools.length > 0) {
7356
- logger.info(`[${this.getProviderName()}] Passing ${executedTools.length} executed tools to component matching`);
7357
7312
  executedToolsText = "The following external tools were executed to fetch data.\n" + executedTools.map((tool, idx) => {
7358
7313
  let outputSchemaText = "Not available";
7359
7314
  let fieldNamesList = "";
@@ -7409,14 +7364,12 @@ ${fieldsText}`;
7409
7364
  KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext,
7410
7365
  CURRENT_DATETIME: getCurrentDateTimeForPrompt()
7411
7366
  });
7412
- logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
7413
7367
  logger.logLLMPrompt("matchComponentsFromAnalysis", "system", extractPromptText(prompts.system));
7414
7368
  logger.logLLMPrompt("matchComponentsFromAnalysis", "user", `Text Analysis:
7415
7369
  ${analysisContent}
7416
7370
 
7417
7371
  Executed Tools:
7418
7372
  ${executedToolsText}`);
7419
- logCollector?.info("Matching components from text response...");
7420
7373
  let fullResponseText = "";
7421
7374
  let answerComponentExtracted = false;
7422
7375
  const answerCallback = componentStreamCallback;
@@ -7476,18 +7429,7 @@ ${executedToolsText}`);
7476
7429
  ...answerComponentData.props
7477
7430
  }
7478
7431
  };
7479
- const streamTime = (/* @__PURE__ */ new Date()).toISOString();
7480
- logger.info(`[${this.getProviderName()}] \u2713 [${streamTime}] Answer component detected in stream: ${answerComponent.name} (${answerComponent.type})`);
7481
- logCollector?.info(`\u2713 Answer component: ${answerComponent.name} (${answerComponent.type}) - detected at ${streamTime}`);
7482
- if (answerComponentData.props?.query) {
7483
- logCollector?.logQuery(
7484
- "Answer component query",
7485
- answerComponentData.props.query,
7486
- { componentName: answerComponent.name, componentType: answerComponent.type, reasoning: answerComponentData.reasoning }
7487
- );
7488
- }
7489
7432
  let answerQuery = answerComponent.props?.query;
7490
- logger.info(`[${this.getProviderName()}] Answer component detected: ${answerComponent.name} (${answerComponent.type}), hasQuery: ${!!answerQuery}, hasDbExecute: ${!!collections?.["database"]?.["execute"]}`);
7491
7433
  if (answerQuery) {
7492
7434
  if (typeof answerQuery === "string") {
7493
7435
  answerQuery = ensureQueryLimit(answerQuery, this.defaultLimit, MAX_COMPONENT_QUERY_LIMIT);
@@ -7505,24 +7447,18 @@ ${executedToolsText}`);
7505
7447
  let currentQuery = answerQuery;
7506
7448
  let currentQueryStr = typeof answerQuery === "string" ? answerQuery : answerQuery?.sql || "";
7507
7449
  let lastError = "";
7508
- logger.info(`[${this.getProviderName()}] Validating answer component query before streaming...`);
7509
7450
  while (attempts < maxRetries && !validated) {
7510
7451
  attempts++;
7511
7452
  try {
7512
7453
  const cacheKey = this.queryService.getQueryCacheKey(currentQuery);
7513
7454
  if (cacheKey) {
7514
- logger.debug(`[${this.getProviderName()}] Answer component query validation attempt ${attempts}/${maxRetries}`);
7515
7455
  const result2 = await collections["database"]["execute"]({ sql: cacheKey });
7516
7456
  queryCache.set(cacheKey, result2);
7517
7457
  validated = true;
7518
7458
  if (currentQuery !== answerQuery) {
7519
7459
  answerComponent.props.query = currentQuery;
7520
7460
  }
7521
- logger.info(`[${this.getProviderName()}] \u2713 Answer component query validated (attempt ${attempts}) - STREAMING TO FRONTEND NOW`);
7522
- logCollector?.info(`\u2713 Answer component query validated - streaming to frontend`);
7523
- logger.info(`[${this.getProviderName()}] Calling answerCallback for: ${answerComponent.name}`);
7524
7461
  answerCallback(answerComponent);
7525
- logger.info(`[${this.getProviderName()}] answerCallback completed for: ${answerComponent.name}`);
7526
7462
  }
7527
7463
  } catch (validationError) {
7528
7464
  lastError = validationError instanceof Error ? validationError.message : String(validationError);
@@ -7558,7 +7494,6 @@ ${executedToolsText}`);
7558
7494
  }
7559
7495
  if (!validated) {
7560
7496
  logger.warn(`[${this.getProviderName()}] Answer component query validation failed after ${attempts} attempts - component will be excluded`);
7561
- logCollector?.warn(`Answer component query validation failed: ${lastError} - component will be excluded from response`);
7562
7497
  }
7563
7498
  })();
7564
7499
  } else {
@@ -7569,7 +7504,7 @@ ${executedToolsText}`);
7569
7504
  }
7570
7505
  }
7571
7506
  } catch (e) {
7572
- logger.debug(`[${this.getProviderName()}] Partial answerComponent parse failed, waiting for more data...`);
7507
+ logger.error(`[${this.getProviderName()}] Partial answerComponent parse failed, waiting for more data...`);
7573
7508
  }
7574
7509
  }
7575
7510
  }
@@ -7599,18 +7534,6 @@ ${executedToolsText}`);
7599
7534
  logger.file("\n=============================\nFull LLM response:", JSON.stringify(result, null, 2));
7600
7535
  const rawActions = result.actions || [];
7601
7536
  const actions = convertQuestionsToActions(rawActions);
7602
- if (matchedComponents.length > 0) {
7603
- matchedComponents.forEach((comp, idx) => {
7604
- logCollector?.info(` ${idx + 1}. ${comp.componentName} (${comp.componentType}): ${comp.reasoning}`);
7605
- if (comp.props?.query) {
7606
- logCollector?.logQuery(
7607
- `Component ${idx + 1} query`,
7608
- comp.props.query,
7609
- { componentName: comp.componentName, title: comp.props.title }
7610
- );
7611
- }
7612
- });
7613
- }
7614
7537
  const finalComponents = matchedComponents.map((mc) => {
7615
7538
  const originalComponent = components.find((c) => c.id === mc.componentId);
7616
7539
  if (!originalComponent) {
@@ -7635,27 +7558,22 @@ ${executedToolsText}`);
7635
7558
  }).filter(Boolean);
7636
7559
  let validatedComponents = finalComponents;
7637
7560
  if (collections?.["database"]?.["execute"]) {
7638
- logger.info(`[${this.getProviderName()}] Starting query validation for ${finalComponents.length} components...`);
7639
- logCollector?.info(`Validating queries for ${finalComponents.length} components...`);
7640
7561
  try {
7641
7562
  const validationResult = await this.queryService.validateComponentQueries(
7642
7563
  finalComponents,
7643
7564
  collections,
7644
- apiKey,
7645
- logCollector
7565
+ apiKey
7646
7566
  );
7647
7567
  validatedComponents = validationResult.components;
7648
7568
  const queriedComponents = finalComponents.filter((c) => c.props?.query);
7649
7569
  const validatedQueries = validatedComponents.filter((c) => c.props?.query);
7650
7570
  logger.info(`[${this.getProviderName()}] Query validation complete: ${validatedQueries.length}/${queriedComponents.length} queries validated`);
7651
- logCollector?.info(`Query validation complete: ${validatedQueries.length}/${queriedComponents.length} queries validated`);
7652
7571
  } catch (validationError) {
7653
7572
  const validationErrorMsg = validationError instanceof Error ? validationError.message : String(validationError);
7654
7573
  logger.error(`[${this.getProviderName()}] Query validation error: ${validationErrorMsg}`);
7655
- logCollector?.error(`Query validation error: ${validationErrorMsg}`);
7656
7574
  }
7657
7575
  } else {
7658
- logger.debug(`[${this.getProviderName()}] Skipping query validation - database execute function not available`);
7576
+ logger.error(`[${this.getProviderName()}] Skipping query validation - database execute function not available`);
7659
7577
  }
7660
7578
  const methodDuration = Date.now() - methodStartTime;
7661
7579
  logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | components: ${validatedComponents.length} | actions: ${actions.length}`);
@@ -7669,7 +7587,6 @@ ${executedToolsText}`);
7669
7587
  const methodDuration = Date.now() - methodStartTime;
7670
7588
  const errorMsg = error instanceof Error ? error.message : String(error);
7671
7589
  logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
7672
- logCollector?.error(`Failed to match components: ${errorMsg}`);
7673
7590
  return {
7674
7591
  components: [],
7675
7592
  layoutTitle: "Dashboard",
@@ -7682,7 +7599,7 @@ ${executedToolsText}`);
7682
7599
  * Classify user question into category and detect external tools needed
7683
7600
  * Determines if question is for data analysis, requires external tools, or needs text response
7684
7601
  */
7685
- async classifyQuestionCategory(userPrompt, apiKey, logCollector, conversationHistory, externalTools) {
7602
+ async classifyQuestionCategory(userPrompt, apiKey, conversationHistory, externalTools) {
7686
7603
  const methodStartTime = Date.now();
7687
7604
  const methodName = "classifyQuestionCategory";
7688
7605
  const promptPreview = userPrompt.substring(0, 50) + (userPrompt.length > 50 ? "..." : "");
@@ -7718,16 +7635,6 @@ ${executedToolsText}`);
7718
7635
  true
7719
7636
  // Parse as JSON
7720
7637
  );
7721
- logCollector?.logExplanation(
7722
- "Question category classified",
7723
- result.reasoning || "No reasoning provided",
7724
- {
7725
- category: result.category,
7726
- externalTools: result.externalTools || [],
7727
- dataAnalysisType: result.dataAnalysisType,
7728
- confidence: result.confidence
7729
- }
7730
- );
7731
7638
  const methodDuration = Date.now() - methodStartTime;
7732
7639
  logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | category: ${result.category} | confidence: ${result.confidence}% | tools: ${(result.externalTools || []).length}`);
7733
7640
  return {
@@ -7741,7 +7648,6 @@ ${executedToolsText}`);
7741
7648
  const methodDuration = Date.now() - methodStartTime;
7742
7649
  const errorMsg = error instanceof Error ? error.message : String(error);
7743
7650
  logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
7744
- logger.debug(`[${this.getProviderName()}] Category classification error details:`, error);
7745
7651
  throw error;
7746
7652
  }
7747
7653
  }
@@ -7750,7 +7656,7 @@ ${executedToolsText}`);
7750
7656
  * Takes a matched UI block from semantic search and modifies its props to answer the new question
7751
7657
  * Also adapts the cached text response to match the new question
7752
7658
  */
7753
- async adaptUIBlockParameters(currentUserPrompt, originalUserPrompt, matchedUIBlock, apiKey, logCollector, cachedTextResponse) {
7659
+ async adaptUIBlockParameters(currentUserPrompt, originalUserPrompt, matchedUIBlock, apiKey, cachedTextResponse) {
7754
7660
  const methodStartTime = Date.now();
7755
7661
  const methodName = "adaptUIBlockParameters";
7756
7662
  const promptPreview = currentUserPrompt.substring(0, 50) + (currentUserPrompt.length > 50 ? "..." : "");
@@ -7794,11 +7700,6 @@ ${executedToolsText}`);
7794
7700
  if (!result.success) {
7795
7701
  const methodDuration2 = Date.now() - methodStartTime;
7796
7702
  logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration2}ms | result: adaptation failed - ${result.reason}`);
7797
- logCollector?.warn(
7798
- "Could not adapt matched UI block",
7799
- "explanation",
7800
- { reason: result.reason }
7801
- );
7802
7703
  return {
7803
7704
  success: false,
7804
7705
  explanation: result.explanation || "Adaptation not possible"
@@ -7810,14 +7711,6 @@ ${executedToolsText}`);
7810
7711
  this.defaultLimit
7811
7712
  );
7812
7713
  }
7813
- logCollector?.logExplanation(
7814
- "UI block parameters adapted",
7815
- result.explanation || "Parameters adapted successfully",
7816
- {
7817
- parametersChanged: result.parametersChanged || [],
7818
- componentType: result.adaptedComponent?.type
7819
- }
7820
- );
7821
7714
  const methodDuration = Date.now() - methodStartTime;
7822
7715
  logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | result: success | changes: ${(result.parametersChanged || []).length}`);
7823
7716
  return {
@@ -7831,7 +7724,6 @@ ${executedToolsText}`);
7831
7724
  const methodDuration = Date.now() - methodStartTime;
7832
7725
  const errorMsg = error instanceof Error ? error.message : String(error);
7833
7726
  logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
7834
- logger.debug(`[${this.getProviderName()}] Adaptation error details:`, error);
7835
7727
  return {
7836
7728
  success: false,
7837
7729
  explanation: `Error adapting parameters: ${errorMsg}`
@@ -7844,14 +7736,12 @@ ${executedToolsText}`);
7844
7736
  * Supports tool calling for query execution with automatic retry on errors (max 3 attempts)
7845
7737
  * After generating text response, if components are provided, matches suggested components
7846
7738
  */
7847
- async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory, streamCallback, collections, components, externalTools, category, userId) {
7739
+ async generateTextResponse(userPrompt, apiKey, conversationHistory, streamCallback, collections, components, externalTools, category, userId) {
7848
7740
  const methodStartTime = Date.now();
7849
7741
  const methodName = "generateTextResponse";
7850
7742
  const promptPreview = userPrompt.substring(0, 50) + (userPrompt.length > 50 ? "..." : "");
7851
7743
  logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("complex")} | category: ${category} | prompt: "${promptPreview}"`);
7852
7744
  const errors = [];
7853
- logger.debug(`[${this.getProviderName()}] Starting text response generation`);
7854
- logger.debug(`[${this.getProviderName()}] User prompt: "${userPrompt.substring(0, 50)}..."`);
7855
7745
  try {
7856
7746
  let availableToolsDoc = "No external tools are available for this request.";
7857
7747
  if (externalTools && externalTools.length > 0) {
@@ -7915,9 +7805,6 @@ ${executedToolsText}`);
7915
7805
  });
7916
7806
  logger.logLLMPrompt("generateTextResponse", "system", extractPromptText(prompts.system));
7917
7807
  logger.logLLMPrompt("generateTextResponse", "user", extractPromptText(prompts.user));
7918
- logger.debug(`[${this.getProviderName()}] Loaded text-response prompts with schema`);
7919
- logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
7920
- logCollector?.info("Generating text response with query execution capability...");
7921
7808
  const tools = [{
7922
7809
  name: "execute_query",
7923
7810
  description: "Executes a parameterized SQL query against the database. CRITICAL: NEVER hardcode literal values in WHERE/HAVING conditions - ALWAYS use $paramName placeholders and pass actual values in params object.",
@@ -7946,7 +7833,6 @@ ${executedToolsText}`);
7946
7833
  const executableTools = externalTools.filter(
7947
7834
  (t) => t.executionType === "immediate" || t.executionType === "deferred" && t.userProvidedData
7948
7835
  );
7949
- logger.info(`[${this.getProviderName()}] Executable tools: ${executableTools.length} of ${externalTools.length} total`);
7950
7836
  const addedToolIds = /* @__PURE__ */ new Set();
7951
7837
  executableTools.forEach((tool) => {
7952
7838
  if (addedToolIds.has(tool.id)) {
@@ -7954,7 +7840,6 @@ ${executedToolsText}`);
7954
7840
  return;
7955
7841
  }
7956
7842
  addedToolIds.add(tool.id);
7957
- logger.info(`[${this.getProviderName()}] Processing executable tool:`, JSON.stringify(tool, null, 2));
7958
7843
  const properties = {};
7959
7844
  const required = [];
7960
7845
  Object.entries(tool.params || {}).forEach(([key, typeOrValue]) => {
@@ -8024,14 +7909,13 @@ ${executedToolsText}`);
8024
7909
  });
8025
7910
  });
8026
7911
  logger.info(`[${this.getProviderName()}] Added ${addedToolIds.size} unique tool definitions from ${executableTools.length} tool calls (${externalTools.length - executableTools.length} deferred tools await form input)`);
8027
- logger.info(`[${this.getProviderName()}] Complete tools array:`, JSON.stringify(tools, null, 2));
7912
+ logger.debug(`[${this.getProviderName()}] Complete tools array:`, JSON.stringify(tools, null, 2));
8028
7913
  }
8029
7914
  const streamBuffer = new StreamBuffer(streamCallback);
8030
7915
  const toolExecutor = new ToolExecutorService({
8031
7916
  providerName: this.getProviderName(),
8032
7917
  collections,
8033
- streamBuffer,
8034
- logCollector
7918
+ streamBuffer
8035
7919
  });
8036
7920
  const executableExternalTools = externalTools?.map((t) => ({
8037
7921
  id: t.id,
@@ -8060,12 +7944,10 @@ ${executedToolsText}`);
8060
7944
  },
8061
7945
  MAX_TOOL_CALLING_ITERATIONS
8062
7946
  );
8063
- logger.info(`[${this.getProviderName()}] Text response stream completed`);
8064
7947
  const textResponse = streamBuffer.getFullText() || result || "I apologize, but I was unable to generate a response.";
8065
7948
  if (toolExecutor.isMaxAttemptsReached()) {
8066
7949
  const methodDuration2 = Date.now() - methodStartTime;
8067
7950
  logger.warn(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration2}ms | result: max attempts reached`);
8068
- logCollector?.error("Failed to generate valid query after maximum attempts");
8069
7951
  return {
8070
7952
  success: false,
8071
7953
  errors: [`Maximum query attempts (${MAX_QUERY_ATTEMPTS}) reached. Unable to generate a valid query for your question.`],
@@ -8077,14 +7959,6 @@ ${executedToolsText}`);
8077
7959
  }
8078
7960
  };
8079
7961
  }
8080
- logCollector?.info(`Text response: ${textResponse.substring(0, 100)}${textResponse.length > 100 ? "..." : ""}`);
8081
- logCollector?.logExplanation(
8082
- "Text response generated",
8083
- "Generated plain text response with component suggestions",
8084
- {
8085
- textLength: textResponse.length
8086
- }
8087
- );
8088
7962
  streamBuffer.flush();
8089
7963
  if (streamBuffer.hasCallback() && components && components.length > 0 && category !== "general") {
8090
7964
  streamBuffer.write("\n\n\u{1F4CA} **Generating visualization components...**\n\n");
@@ -8096,8 +7970,6 @@ ${executedToolsText}`);
8096
7970
  let actions = [];
8097
7971
  if (category === "general") {
8098
7972
  logger.info(`[${this.getProviderName()}] Skipping component generation for general/conversational question`);
8099
- logCollector?.info("Skipping component generation for general question");
8100
- logger.info(`[${this.getProviderName()}] Generating actions for general question...`);
8101
7973
  const nextQuestions = await this.generateNextQuestions(
8102
7974
  userPrompt,
8103
7975
  null,
@@ -8105,23 +7977,16 @@ ${executedToolsText}`);
8105
7977
  void 0,
8106
7978
  // no component data
8107
7979
  apiKey,
8108
- logCollector,
8109
7980
  conversationHistory,
8110
7981
  textResponse
8111
7982
  // pass text response as context
8112
7983
  );
8113
7984
  actions = convertQuestionsToActions(nextQuestions);
8114
- logger.info(`[${this.getProviderName()}] Generated ${actions.length} follow-up actions for general question`);
8115
7985
  } else if (components && components.length > 0) {
8116
- logger.info(`[${this.getProviderName()}] Matching components from text response...`);
8117
- logger.info(`[${this.getProviderName()}] componentStreamCallback setup: hasCallback=${streamBuffer.hasCallback()}, category=${category}`);
8118
- const componentStreamCallback = streamBuffer.hasCallback() && category !== "data_modification" ? (component) => {
8119
- logger.info(`[${this.getProviderName()}] componentStreamCallback INVOKED for: ${component.name} (${component.type})`);
7986
+ const componentStreamCallback = streamBuffer.hasCallback() && category === "data_analysis" ? (component) => {
8120
7987
  const answerMarker = `__ANSWER_COMPONENT_START__${JSON.stringify(component)}__ANSWER_COMPONENT_END__`;
8121
7988
  streamBuffer.write(answerMarker);
8122
- logger.info(`[${this.getProviderName()}] Streamed answer component to frontend: ${component.name} (${component.type})`);
8123
7989
  } : void 0;
8124
- logger.info(`[${this.getProviderName()}] componentStreamCallback created: ${!!componentStreamCallback}`);
8125
7990
  const deferredTools = externalTools?.filter((t) => {
8126
7991
  if (t.executionType === "deferred" && !t.userProvidedData) return true;
8127
7992
  if (category === "data_modification" && !t.userProvidedData) {
@@ -8142,7 +8007,6 @@ ${executedToolsText}`);
8142
8007
  components,
8143
8008
  userPrompt,
8144
8009
  apiKey,
8145
- logCollector,
8146
8010
  componentStreamCallback,
8147
8011
  deferredTools,
8148
8012
  toolExecutor.getExecutedTools(),
@@ -8156,8 +8020,6 @@ ${executedToolsText}`);
8156
8020
  }
8157
8021
  let container_componet = null;
8158
8022
  if (matchedComponents.length > 0) {
8159
- logger.info(`[${this.getProviderName()}] Created MultiComponentContainer: "${layoutTitle}" with ${matchedComponents.length} components and ${actions.length} actions`);
8160
- logCollector?.info(`Created dashboard: "${layoutTitle}" with ${matchedComponents.length} components and ${actions.length} actions`);
8161
8023
  container_componet = {
8162
8024
  id: `container_${Date.now()}`,
8163
8025
  name: "MultiComponentContainer",
@@ -8189,7 +8051,6 @@ ${executedToolsText}`);
8189
8051
  const methodDuration = Date.now() - methodStartTime;
8190
8052
  const errorMsg = error instanceof Error ? error.message : String(error);
8191
8053
  logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
8192
- logCollector?.error(`Error generating text response: ${errorMsg}`);
8193
8054
  userPromptErrorLogger.logLlmError(
8194
8055
  this.getProviderName(),
8195
8056
  this.model,
@@ -8217,14 +8078,11 @@ ${executedToolsText}`);
8217
8078
  * 2. Category classification: Determine if data_analysis, requires_external_tools, or text_response
8218
8079
  * 3. Route appropriately based on category and response mode
8219
8080
  */
8220
- async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory, responseMode = "text", streamCallback, collections, externalTools, userId) {
8081
+ async handleUserRequest(userPrompt, components, apiKey, conversationHistory, responseMode = "text", streamCallback, collections, externalTools, userId) {
8221
8082
  const startTime = Date.now();
8222
- logger.info(`[${this.getProviderName()}] handleUserRequest called for user prompt: ${userPrompt}`);
8223
- logCollector?.info(`Starting request processing with mode: ${responseMode}`);
8224
8083
  logger.clearFile();
8225
8084
  logger.logLLMPrompt("handleUserRequest", "user", `User Prompt: ${userPrompt}`);
8226
8085
  try {
8227
- logger.info(`[${this.getProviderName()}] Step 1: Searching previous conversations...`);
8228
8086
  const conversationMatch = await conversation_search_default.searchConversationsWithReranking({
8229
8087
  userPrompt,
8230
8088
  collections,
@@ -8233,22 +8091,16 @@ ${executedToolsText}`);
8233
8091
  });
8234
8092
  if (conversationMatch) {
8235
8093
  logger.info(`[${this.getProviderName()}] \u2713 Found matching conversation with ${(conversationMatch.similarity * 100).toFixed(2)}% similarity`);
8236
- logCollector?.info(
8237
- `\u2713 Found similar conversation (${(conversationMatch.similarity * 100).toFixed(2)}% match)`
8238
- );
8239
8094
  const rawComponent = conversationMatch.uiBlock?.component || conversationMatch.uiBlock?.generatedComponentMetadata;
8240
8095
  const isValidComponent = rawComponent && typeof rawComponent === "object" && Object.keys(rawComponent).length > 0;
8241
8096
  const component = isValidComponent ? rawComponent : null;
8242
8097
  const cachedTextResponse = conversationMatch.uiBlock?.analysis || conversationMatch.uiBlock?.textResponse || conversationMatch.uiBlock?.text || "";
8243
8098
  if (this.containsFormComponent(component)) {
8244
8099
  logger.info(`[${this.getProviderName()}] Skipping cached result - Form components contain stale defaultValues, fetching fresh data`);
8245
- logCollector?.info("Skipping cache for form - fetching current values from database...");
8246
8100
  } else if (!component) {
8247
8101
  if (conversationMatch.similarity >= EXACT_MATCH_SIMILARITY_THRESHOLD) {
8248
8102
  const elapsedTime2 = Date.now() - startTime;
8249
- logger.info(`[${this.getProviderName()}] \u2713 Exact match for general question - returning cached text response`);
8250
- logCollector?.info(`\u2713 Exact match for general question - returning cached response`);
8251
- logCollector?.info(`Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
8103
+ logger.info(`[${this.getProviderName()}] \u2713 Exact match for general question - returning cached text response (${elapsedTime2}ms)`);
8252
8104
  return {
8253
8105
  success: true,
8254
8106
  data: {
@@ -8263,14 +8115,11 @@ ${executedToolsText}`);
8263
8115
  };
8264
8116
  } else {
8265
8117
  logger.info(`[${this.getProviderName()}] Similar match but no component (general question) - processing fresh`);
8266
- logCollector?.info("Similar match found but was a general conversation - processing as new question");
8267
8118
  }
8268
8119
  } else {
8269
8120
  if (conversationMatch.similarity >= EXACT_MATCH_SIMILARITY_THRESHOLD) {
8270
8121
  const elapsedTime2 = Date.now() - startTime;
8271
- logger.info(`[${this.getProviderName()}] \u2713 100% match - returning UI block directly without adaptation`);
8272
- logCollector?.info(`\u2713 Exact match (${(conversationMatch.similarity * 100).toFixed(2)}%) - returning cached result`);
8273
- logCollector?.info(`Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
8122
+ logger.info(`[${this.getProviderName()}] \u2713 100% match - returning UI block directly without adaptation (${elapsedTime2}ms)`);
8274
8123
  if (streamCallback && cachedTextResponse) {
8275
8124
  logger.info(`[${this.getProviderName()}] Streaming cached text response to frontend`);
8276
8125
  streamCallback(cachedTextResponse);
@@ -8289,22 +8138,18 @@ ${executedToolsText}`);
8289
8138
  errors: []
8290
8139
  };
8291
8140
  }
8292
- logCollector?.info(`Adapting parameters for similar question...`);
8141
+ logger.info(`[${this.getProviderName()}] Adapting parameters for similar question...`);
8293
8142
  const originalPrompt = conversationMatch.metadata?.userPrompt || "Previous question";
8294
8143
  const adaptResult = await this.adaptUIBlockParameters(
8295
8144
  userPrompt,
8296
8145
  originalPrompt,
8297
8146
  conversationMatch.uiBlock,
8298
8147
  apiKey,
8299
- logCollector,
8300
8148
  cachedTextResponse
8301
8149
  );
8302
8150
  if (adaptResult.success && adaptResult.adaptedComponent) {
8303
8151
  const elapsedTime2 = Date.now() - startTime;
8304
- logger.info(`[${this.getProviderName()}] \u2713 Successfully adapted UI block parameters`);
8305
- logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
8306
- logCollector?.info(`\u2713 UI block adapted successfully`);
8307
- logCollector?.info(`Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
8152
+ logger.info(`[${this.getProviderName()}] \u2713 Successfully adapted UI block parameters (${elapsedTime2}ms)`);
8308
8153
  const textResponseToUse = adaptResult.adaptedTextResponse || cachedTextResponse;
8309
8154
  if (streamCallback && textResponseToUse) {
8310
8155
  logger.info(`[${this.getProviderName()}] Streaming ${adaptResult.adaptedTextResponse ? "adapted" : "cached"} text response to frontend`);
@@ -8325,65 +8170,57 @@ ${executedToolsText}`);
8325
8170
  errors: []
8326
8171
  };
8327
8172
  } else {
8328
- logger.info(`[${this.getProviderName()}] Could not adapt matched conversation, continuing to category classification`);
8329
- logCollector?.warn(`Could not adapt matched conversation: ${adaptResult.explanation}`);
8173
+ logger.info(`[${this.getProviderName()}] Could not adapt matched conversation: ${adaptResult.explanation}, continuing to category classification`);
8330
8174
  }
8331
8175
  }
8332
8176
  } else {
8333
8177
  logger.info(`[${this.getProviderName()}] No matching previous conversations found, proceeding to category classification`);
8334
- logCollector?.info("No similar previous conversations found. Proceeding to category classification...");
8335
8178
  }
8336
8179
  logger.info(`[${this.getProviderName()}] Step 2: Classifying question category...`);
8337
- logCollector?.info("Step 2: Classifying question category...");
8338
8180
  const categoryClassification = await this.classifyQuestionCategory(
8339
8181
  userPrompt,
8340
8182
  apiKey,
8341
- logCollector,
8342
8183
  conversationHistory,
8343
8184
  externalTools
8344
8185
  );
8345
8186
  logger.info(
8346
8187
  `[${this.getProviderName()}] Question classified as: ${categoryClassification.category} (confidence: ${categoryClassification.confidence}%)`
8347
8188
  );
8348
- logCollector?.info(
8349
- `Category: ${categoryClassification.category} | Confidence: ${categoryClassification.confidence}%`
8350
- );
8351
8189
  let toolsToUse = [];
8352
8190
  if (categoryClassification.externalTools && categoryClassification.externalTools.length > 0) {
8353
- logger.info(`[${this.getProviderName()}] Identified ${categoryClassification.externalTools.length} external tools needed`);
8354
- logCollector?.info(`Identified external tools: ${categoryClassification.externalTools.map((t) => t.name || t.type).join(", ")}`);
8355
- logger.info(`[${this.getProviderName()}] Raw external tools from classification: ${JSON.stringify(categoryClassification.externalTools, null, 2)}`);
8356
- toolsToUse = categoryClassification.externalTools?.map((t) => {
8191
+ logger.info(`[${this.getProviderName()}] Identified ${categoryClassification.externalTools.length} external tools needed: ${categoryClassification.externalTools.map((t) => t.name || t.type).join(", ")}`);
8192
+ logger.debug(`[${this.getProviderName()}] Raw external tools from classification: ${JSON.stringify(categoryClassification.externalTools, null, 2)}`);
8193
+ toolsToUse = categoryClassification.externalTools.reduce((acc, t) => {
8357
8194
  const realTool = externalTools?.find((tool) => tool.id === t.type);
8358
- logger.info(`[${this.getProviderName()}] Tool ${t.name}: executionType=${t.executionType}, userProvidedData=${t.userProvidedData ? "present" : "null"}`);
8359
- return {
8195
+ if (!realTool) {
8196
+ logger.warn(`[${this.getProviderName()}] Tool ${t.type} (${t.name}) not found in registered tools - skipping (likely hallucinated)`);
8197
+ return acc;
8198
+ }
8199
+ acc.push({
8360
8200
  id: t.type,
8361
8201
  name: t.name,
8362
8202
  description: t.description,
8363
8203
  params: t.parameters || {},
8364
- // NEW: Include execution type info from category classification
8204
+ // Include execution type info from category classification
8365
8205
  executionType: t.executionType || "immediate",
8366
8206
  executionReason: t.executionReason || "",
8367
8207
  requiredFields: t.requiredFields || [],
8368
8208
  userProvidedData: t.userProvidedData || null,
8369
- // CRITICAL: Include outputSchema from real tool for component config generation
8370
- outputSchema: realTool?.outputSchema,
8371
- fn: (() => {
8372
- if (realTool) {
8373
- logger.info(`[${this.getProviderName()}] Using real tool implementation for ${t.type}`);
8374
- return realTool.fn;
8375
- } else {
8376
- logger.warn(`[${this.getProviderName()}] Tool ${t.type} not found in registered tools`);
8377
- return async () => ({ success: false, message: `Tool ${t.name || t.type} not registered` });
8378
- }
8379
- })()
8380
- };
8381
- }) || [];
8209
+ // Include outputSchema from real tool for component config generation
8210
+ outputSchema: realTool.outputSchema,
8211
+ fn: realTool.fn
8212
+ });
8213
+ return acc;
8214
+ }, []);
8215
+ const validCount = toolsToUse.length;
8216
+ const hallucinatedCount = categoryClassification.externalTools.length - validCount;
8217
+ if (hallucinatedCount > 0) {
8218
+ logger.warn(`[${this.getProviderName()}] Filtered out ${hallucinatedCount} hallucinated/non-existent tools, ${validCount} valid tools remaining`);
8219
+ }
8382
8220
  }
8383
8221
  const textResponse = await this.generateTextResponse(
8384
8222
  userPrompt,
8385
8223
  apiKey,
8386
- logCollector,
8387
8224
  conversationHistory,
8388
8225
  streamCallback,
8389
8226
  collections,
@@ -8394,13 +8231,10 @@ ${executedToolsText}`);
8394
8231
  );
8395
8232
  const elapsedTime = Date.now() - startTime;
8396
8233
  logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
8397
- logCollector?.info(`Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
8398
8234
  return textResponse;
8399
8235
  } catch (error) {
8400
8236
  const errorMsg = error instanceof Error ? error.message : String(error);
8401
8237
  logger.error(`[${this.getProviderName()}] Error in handleUserRequest: ${errorMsg}`);
8402
- logger.debug(`[${this.getProviderName()}] Error details:`, error);
8403
- logCollector?.error(`Error processing request: ${errorMsg}`);
8404
8238
  userPromptErrorLogger.logError(
8405
8239
  "handleUserRequest",
8406
8240
  error instanceof Error ? error : new Error(errorMsg),
@@ -8408,7 +8242,6 @@ ${executedToolsText}`);
8408
8242
  );
8409
8243
  const elapsedTime = Date.now() - startTime;
8410
8244
  logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
8411
- logCollector?.info(`Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
8412
8245
  return {
8413
8246
  success: false,
8414
8247
  errors: [errorMsg],
@@ -8424,7 +8257,7 @@ ${executedToolsText}`);
8424
8257
  * This helps provide intelligent suggestions for follow-up queries
8425
8258
  * For general/conversational questions without components, pass textResponse instead
8426
8259
  */
8427
- async generateNextQuestions(originalUserPrompt, component, componentData, apiKey, logCollector, conversationHistory, textResponse) {
8260
+ async generateNextQuestions(originalUserPrompt, component, componentData, apiKey, conversationHistory, textResponse) {
8428
8261
  const methodStartTime = Date.now();
8429
8262
  const methodName = "generateNextQuestions";
8430
8263
  const promptPreview = originalUserPrompt.substring(0, 50) + (originalUserPrompt.length > 50 ? "..." : "");
@@ -8469,14 +8302,6 @@ ${executedToolsText}`);
8469
8302
  // Parse as JSON
8470
8303
  );
8471
8304
  const nextQuestions = result.nextQuestions || [];
8472
- logCollector?.logExplanation(
8473
- "Next questions generated",
8474
- "Generated intelligent follow-up questions based on component",
8475
- {
8476
- count: nextQuestions.length,
8477
- questions: nextQuestions
8478
- }
8479
- );
8480
8305
  const methodDuration = Date.now() - methodStartTime;
8481
8306
  logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | questions: ${nextQuestions.length}`);
8482
8307
  return nextQuestions;
@@ -8484,8 +8309,6 @@ ${executedToolsText}`);
8484
8309
  const methodDuration = Date.now() - methodStartTime;
8485
8310
  const errorMsg = error instanceof Error ? error.message : String(error);
8486
8311
  logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
8487
- logger.debug(`[${this.getProviderName()}] Next questions generation error details:`, error);
8488
- logCollector?.error(`Error generating next questions: ${errorMsg}`);
8489
8312
  return [];
8490
8313
  }
8491
8314
  }
@@ -8599,332 +8422,96 @@ function getLLMProviders() {
8599
8422
  return DEFAULT_PROVIDERS;
8600
8423
  }
8601
8424
  }
8602
- var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8603
- logger.debug("[useAnthropicMethod] Initializing Anthropic Claude matching method");
8604
- logger.debug(`[useAnthropicMethod] Response mode: ${responseMode}`);
8605
- const msg = `Using Anthropic Claude ${responseMode === "text" ? "text response" : "matching"} method...`;
8606
- logCollector?.info(msg);
8425
+ var useAnthropicMethod = async (prompt, components, apiKey, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8607
8426
  if (responseMode === "component" && components.length === 0) {
8608
8427
  const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
8609
8428
  logger.error("[useAnthropicMethod] No components available");
8610
- logCollector?.error(emptyMsg);
8611
8429
  return { success: false, errors: [emptyMsg] };
8612
8430
  }
8613
- logger.debug(`[useAnthropicMethod] Processing with ${components.length} components`);
8614
- const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8431
+ const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8615
8432
  logger.info(`[useAnthropicMethod] Successfully generated ${responseMode} using Anthropic`);
8616
8433
  return matchResult;
8617
8434
  };
8618
- var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8435
+ var useGroqMethod = async (prompt, components, apiKey, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8619
8436
  logger.debug("[useGroqMethod] Initializing Groq LLM matching method");
8620
8437
  logger.debug(`[useGroqMethod] Response mode: ${responseMode}`);
8621
- const msg = `Using Groq LLM ${responseMode === "text" ? "text response" : "matching"} method...`;
8622
- logger.info(msg);
8623
- logCollector?.info(msg);
8624
8438
  if (responseMode === "component" && components.length === 0) {
8625
8439
  const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
8626
8440
  logger.error("[useGroqMethod] No components available");
8627
- logCollector?.error(emptyMsg);
8628
8441
  return { success: false, errors: [emptyMsg] };
8629
8442
  }
8630
8443
  logger.debug(`[useGroqMethod] Processing with ${components.length} components`);
8631
- const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8444
+ const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8632
8445
  logger.info(`[useGroqMethod] Successfully generated ${responseMode} using Groq`);
8633
8446
  return matchResult;
8634
8447
  };
8635
- var useGeminiMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8448
+ var useGeminiMethod = async (prompt, components, apiKey, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8636
8449
  logger.debug("[useGeminiMethod] Initializing Gemini LLM matching method");
8637
8450
  logger.debug(`[useGeminiMethod] Response mode: ${responseMode}`);
8638
- const msg = `Using Gemini LLM ${responseMode === "text" ? "text response" : "matching"} method...`;
8639
- logger.info(msg);
8640
- logCollector?.info(msg);
8641
8451
  if (responseMode === "component" && components.length === 0) {
8642
8452
  const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
8643
8453
  logger.error("[useGeminiMethod] No components available");
8644
- logCollector?.error(emptyMsg);
8645
8454
  return { success: false, errors: [emptyMsg] };
8646
8455
  }
8647
8456
  logger.debug(`[useGeminiMethod] Processing with ${components.length} components`);
8648
- const matchResult = await geminiLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8457
+ const matchResult = await geminiLLM.handleUserRequest(prompt, components, apiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8649
8458
  logger.info(`[useGeminiMethod] Successfully generated ${responseMode} using Gemini`);
8650
8459
  return matchResult;
8651
8460
  };
8652
- var useOpenAIMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8461
+ var useOpenAIMethod = async (prompt, components, apiKey, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8653
8462
  logger.debug("[useOpenAIMethod] Initializing OpenAI GPT matching method");
8654
8463
  logger.debug(`[useOpenAIMethod] Response mode: ${responseMode}`);
8655
- const msg = `Using OpenAI GPT ${responseMode === "text" ? "text response" : "matching"} method...`;
8656
- logger.info(msg);
8657
- logCollector?.info(msg);
8658
8464
  if (responseMode === "component" && components.length === 0) {
8659
8465
  const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
8660
8466
  logger.error("[useOpenAIMethod] No components available");
8661
- logCollector?.error(emptyMsg);
8662
8467
  return { success: false, errors: [emptyMsg] };
8663
8468
  }
8664
8469
  logger.debug(`[useOpenAIMethod] Processing with ${components.length} components`);
8665
- const matchResult = await openaiLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8470
+ const matchResult = await openaiLLM.handleUserRequest(prompt, components, apiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8666
8471
  logger.info(`[useOpenAIMethod] Successfully generated ${responseMode} using OpenAI`);
8667
8472
  return matchResult;
8668
8473
  };
8669
- var getUserResponseFromCache = async (prompt) => {
8670
- return false;
8671
- };
8672
- var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8673
- logger.debug(`[get_user_response] Starting user response generation for prompt: "${prompt.substring(0, 50)}..."`);
8674
- logger.debug(`[get_user_response] Response mode: ${responseMode}`);
8675
- logger.debug("[get_user_response] Checking cache for existing response");
8676
- const userResponse = await getUserResponseFromCache(prompt);
8677
- if (userResponse) {
8678
- logger.info("[get_user_response] User response found in cache - returning cached result");
8679
- logCollector?.info("User response found in cache");
8680
- return {
8681
- success: true,
8682
- data: userResponse,
8683
- errors: []
8684
- };
8685
- }
8686
- logger.debug("[get_user_response] No cached response found, proceeding with LLM providers");
8474
+ var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8687
8475
  const providers = llmProviders || getLLMProviders();
8688
8476
  const errors = [];
8689
- const providerOrder = providers.join(", ");
8690
- logCollector?.info(`LLM Provider order: [${providerOrder}]`);
8691
- if (conversationHistory && conversationHistory.length > 0) {
8692
- const exchangeCount = conversationHistory.split("\n").filter((l) => l.startsWith("Q")).length;
8693
- logger.debug(`[get_user_response] Using conversation history with ${exchangeCount} previous exchanges`);
8694
- logCollector?.info(`Using conversation history with ${exchangeCount} previous exchanges`);
8695
- } else {
8696
- logger.debug("[get_user_response] No conversation history available");
8697
- }
8477
+ logger.info(`[get_user_response] LLM Provider order: [${providers.join(", ")}]`);
8698
8478
  for (let i = 0; i < providers.length; i++) {
8699
8479
  const provider = providers[i];
8700
8480
  const isLastProvider = i === providers.length - 1;
8701
- const attemptMsg = `Attempting provider: ${provider} (${i + 1}/${providers.length})`;
8702
- logCollector?.info(attemptMsg);
8481
+ logger.info(`[get_user_response] Attempting provider: ${provider} (${i + 1}/${providers.length})`);
8703
8482
  let result;
8704
8483
  if (provider === "anthropic") {
8705
- result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8484
+ result = await useAnthropicMethod(prompt, components, anthropicApiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8706
8485
  } else if (provider === "groq") {
8707
- result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8486
+ result = await useGroqMethod(prompt, components, groqApiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8708
8487
  } else if (provider === "gemini") {
8709
- result = await useGeminiMethod(prompt, components, geminiApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8488
+ result = await useGeminiMethod(prompt, components, geminiApiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8710
8489
  } else if (provider === "openai") {
8711
- result = await useOpenAIMethod(prompt, components, openaiApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8490
+ result = await useOpenAIMethod(prompt, components, openaiApiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8712
8491
  } else {
8713
8492
  logger.warn(`[get_user_response] Unknown provider: ${provider} - skipping`);
8714
8493
  errors.push(`Unknown provider: ${provider}`);
8715
8494
  continue;
8716
8495
  }
8717
8496
  if (result.success) {
8718
- const successMsg = `Success with provider: ${provider}`;
8719
- logger.info(`${successMsg}`);
8720
- logCollector?.info(successMsg);
8497
+ logger.info(`[get_user_response] Success with provider: ${provider}`);
8721
8498
  return result;
8722
8499
  } else {
8723
8500
  const providerErrors = result.errors.map((err) => `${provider}: ${err}`);
8724
8501
  errors.push(...providerErrors);
8725
- const warnMsg = `Provider ${provider} returned unsuccessful result: ${result.errors.join(", ")}`;
8726
- logger.warn(`[get_user_response] ${warnMsg}`);
8727
- logCollector?.warn(warnMsg);
8502
+ logger.warn(`[get_user_response] Provider ${provider} returned unsuccessful result: ${result.errors.join(", ")}`);
8728
8503
  if (!isLastProvider) {
8729
- const fallbackMsg = "Falling back to next provider...";
8730
- logger.info(`[get_user_response] ${fallbackMsg}`);
8731
- logCollector?.info(fallbackMsg);
8504
+ logger.info("[get_user_response] Falling back to next provider...");
8732
8505
  }
8733
8506
  }
8734
8507
  }
8735
- const failureMsg = `All LLM providers failed`;
8736
- logger.error(`[get_user_response] ${failureMsg}. Errors: ${errors.join("; ")}`);
8737
- logCollector?.error(`${failureMsg}. Errors: ${errors.join("; ")}`);
8508
+ logger.error(`[get_user_response] All LLM providers failed. Errors: ${errors.join("; ")}`);
8738
8509
  return {
8739
8510
  success: false,
8740
8511
  errors
8741
8512
  };
8742
8513
  };
8743
8514
 
8744
- // src/utils/log-collector.ts
8745
- var LOG_LEVEL_PRIORITY2 = {
8746
- errors: 0,
8747
- warnings: 1,
8748
- info: 2,
8749
- verbose: 3
8750
- };
8751
- var MESSAGE_LEVEL_PRIORITY2 = {
8752
- error: 0,
8753
- warn: 1,
8754
- info: 2,
8755
- debug: 3
8756
- };
8757
- var UILogCollector = class {
8758
- constructor(clientId, sendMessage, uiBlockId) {
8759
- this.logs = [];
8760
- this.uiBlockId = uiBlockId || null;
8761
- this.clientId = clientId;
8762
- this.sendMessage = sendMessage;
8763
- this.currentLogLevel = logger.getLogLevel();
8764
- }
8765
- /**
8766
- * Check if logging is enabled (uiBlockId is provided)
8767
- */
8768
- isEnabled() {
8769
- return this.uiBlockId !== null;
8770
- }
8771
- /**
8772
- * Check if a message should be logged based on current log level
8773
- */
8774
- shouldLog(messageLevel) {
8775
- const currentLevelPriority = LOG_LEVEL_PRIORITY2[this.currentLogLevel];
8776
- const messagePriority = MESSAGE_LEVEL_PRIORITY2[messageLevel];
8777
- return messagePriority <= currentLevelPriority;
8778
- }
8779
- /**
8780
- * Add a log entry with timestamp and immediately send to runtime
8781
- * Only logs that pass the log level filter are captured and sent
8782
- */
8783
- addLog(level, message, type, data) {
8784
- if (!this.shouldLog(level)) {
8785
- return;
8786
- }
8787
- const log = {
8788
- timestamp: Date.now(),
8789
- level,
8790
- message,
8791
- ...type && { type },
8792
- ...data && { data }
8793
- };
8794
- this.logs.push(log);
8795
- this.sendLogImmediately(log);
8796
- switch (level) {
8797
- case "error":
8798
- logger.error("UILogCollector:", log);
8799
- break;
8800
- case "warn":
8801
- logger.warn("UILogCollector:", log);
8802
- break;
8803
- case "info":
8804
- logger.info("UILogCollector:", log);
8805
- break;
8806
- case "debug":
8807
- logger.debug("UILogCollector:", log);
8808
- break;
8809
- }
8810
- }
8811
- /**
8812
- * Send a single log to runtime immediately
8813
- */
8814
- sendLogImmediately(log) {
8815
- if (!this.isEnabled()) {
8816
- return;
8817
- }
8818
- const response = {
8819
- id: this.uiBlockId,
8820
- type: "UI_LOGS",
8821
- from: { type: "data-agent" },
8822
- to: {
8823
- type: "runtime",
8824
- id: this.clientId
8825
- },
8826
- payload: {
8827
- logs: [log]
8828
- // Send single log in array
8829
- }
8830
- };
8831
- this.sendMessage(response);
8832
- }
8833
- /**
8834
- * Log info message
8835
- */
8836
- info(message, type, data) {
8837
- if (this.isEnabled()) {
8838
- this.addLog("info", message, type, data);
8839
- }
8840
- }
8841
- /**
8842
- * Log error message
8843
- */
8844
- error(message, type, data) {
8845
- if (this.isEnabled()) {
8846
- this.addLog("error", message, type, data);
8847
- }
8848
- }
8849
- /**
8850
- * Log warning message
8851
- */
8852
- warn(message, type, data) {
8853
- if (this.isEnabled()) {
8854
- this.addLog("warn", message, type, data);
8855
- }
8856
- }
8857
- /**
8858
- * Log debug message
8859
- */
8860
- debug(message, type, data) {
8861
- if (this.isEnabled()) {
8862
- this.addLog("debug", message, type, data);
8863
- }
8864
- }
8865
- /**
8866
- * Log LLM explanation with typed metadata
8867
- */
8868
- logExplanation(message, explanation, data) {
8869
- if (this.isEnabled()) {
8870
- this.addLog("info", message, "explanation", {
8871
- explanation,
8872
- ...data
8873
- });
8874
- }
8875
- }
8876
- /**
8877
- * Log generated query with typed metadata
8878
- */
8879
- logQuery(message, query, data) {
8880
- if (this.isEnabled()) {
8881
- this.addLog("info", message, "query", {
8882
- query,
8883
- ...data
8884
- });
8885
- }
8886
- }
8887
- /**
8888
- * Send all collected logs at once (optional, for final summary)
8889
- */
8890
- sendAllLogs() {
8891
- if (!this.isEnabled() || this.logs.length === 0) {
8892
- return;
8893
- }
8894
- const response = {
8895
- id: this.uiBlockId,
8896
- type: "UI_LOGS",
8897
- from: { type: "data-agent" },
8898
- to: {
8899
- type: "runtime",
8900
- id: this.clientId
8901
- },
8902
- payload: {
8903
- logs: this.logs
8904
- }
8905
- };
8906
- this.sendMessage(response);
8907
- }
8908
- /**
8909
- * Get all collected logs
8910
- */
8911
- getLogs() {
8912
- return [...this.logs];
8913
- }
8914
- /**
8915
- * Clear all logs
8916
- */
8917
- clearLogs() {
8918
- this.logs = [];
8919
- }
8920
- /**
8921
- * Set uiBlockId (in case it's provided later)
8922
- */
8923
- setUIBlockId(uiBlockId) {
8924
- this.uiBlockId = uiBlockId;
8925
- }
8926
- };
8927
-
8928
8515
  // src/utils/conversation-saver.ts
8929
8516
  function transformUIBlockForDB(uiblock, userPrompt, uiBlockId) {
8930
8517
  const component = uiblock?.generatedComponentMetadata && Object.keys(uiblock.generatedComponentMetadata).length > 0 ? uiblock.generatedComponentMetadata : null;
@@ -9055,7 +8642,6 @@ var CONTEXT_CONFIG = {
9055
8642
  // src/handlers/user-prompt-request.ts
9056
8643
  var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools) => {
9057
8644
  const errors = [];
9058
- logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
9059
8645
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
9060
8646
  if (!parseResult.success) {
9061
8647
  const zodError = parseResult.error;
@@ -9087,27 +8673,23 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
9087
8673
  if (!prompt) {
9088
8674
  errors.push("Prompt not found");
9089
8675
  }
9090
- logger.debug(`[REQUEST ${id}] Full request details - uiBlockId: ${existingUiBlockId}, threadId: ${threadId}, prompt: ${prompt}`);
9091
8676
  if (errors.length > 0) {
9092
8677
  return { success: false, errors, id, wsId };
9093
8678
  }
9094
- const logCollector = new UILogCollector(wsId, sendMessage, existingUiBlockId);
9095
8679
  const threadManager = ThreadManager.getInstance();
9096
8680
  let thread = threadManager.getThread(threadId);
9097
8681
  if (!thread) {
9098
8682
  thread = threadManager.createThread(threadId);
9099
8683
  logger.info(`Created new thread: ${threadId}`);
9100
8684
  }
9101
- logCollector.info(`Starting user prompt request with ${components.length} components`);
8685
+ logger.info(`Starting user prompt request with ${components.length} components`);
9102
8686
  const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
9103
8687
  const responseMode = payload.responseMode || "component";
9104
- logger.info("responseMode", responseMode);
9105
8688
  let streamCallback;
9106
8689
  let accumulatedStreamResponse = "";
9107
8690
  if (responseMode === "text") {
9108
8691
  streamCallback = (chunk) => {
9109
8692
  accumulatedStreamResponse += chunk;
9110
- logger.debug(`[STREAM] Sending chunk (${chunk.length} chars): "${chunk.substring(0, 20)}..."`);
9111
8693
  const streamMessage = {
9112
8694
  id: `stream_${existingUiBlockId}`,
9113
8695
  // Different ID pattern for streaming
@@ -9123,7 +8705,6 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
9123
8705
  }
9124
8706
  };
9125
8707
  sendMessage(streamMessage);
9126
- logger.debug(`[STREAM] Chunk sent to wsId: ${wsId}`);
9127
8708
  };
9128
8709
  }
9129
8710
  const userResponse = await get_user_response(
@@ -9134,7 +8715,6 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
9134
8715
  geminiApiKey,
9135
8716
  openaiApiKey,
9136
8717
  llmProviders,
9137
- logCollector,
9138
8718
  conversationHistory,
9139
8719
  responseMode,
9140
8720
  streamCallback,
@@ -9142,7 +8722,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
9142
8722
  externalTools,
9143
8723
  userId
9144
8724
  );
9145
- logCollector.info("User prompt request completed");
8725
+ logger.info("User prompt request completed");
9146
8726
  const uiBlockId = existingUiBlockId;
9147
8727
  if (!userResponse.success) {
9148
8728
  logger.error(`User prompt request failed with errors: ${userResponse.errors.join(", ")}`);
@@ -9209,9 +8789,6 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
9209
8789
  logger.info(
9210
8790
  `Skipping conversation save - response from exact semantic match (${(semanticSimilarity * 100).toFixed(2)}% similarity)`
9211
8791
  );
9212
- logCollector.info(
9213
- `Using exact cached result (${(semanticSimilarity * 100).toFixed(2)}% match) - not saving duplicate conversation`
9214
- );
9215
8792
  } else {
9216
8793
  const uiBlockData = uiBlock.toJSON();
9217
8794
  const saveResult = await saveConversation({
@@ -9419,7 +8996,7 @@ function sendResponse(id, res, sendMessage, clientId) {
9419
8996
  }
9420
8997
 
9421
8998
  // src/userResponse/next-questions.ts
9422
- async function generateNextQuestions(originalUserPrompt, component, componentData, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, logCollector, conversationHistory) {
8999
+ async function generateNextQuestions(originalUserPrompt, component, componentData, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, conversationHistory) {
9423
9000
  try {
9424
9001
  logger.debug("[generateNextQuestions] Starting next questions generation");
9425
9002
  logger.debug(`[generateNextQuestions] User prompt: "${originalUserPrompt?.substring(0, 50)}..."`);
@@ -9438,7 +9015,6 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
9438
9015
  const isLastProvider = i === providers.length - 1;
9439
9016
  try {
9440
9017
  logger.info(`[generateNextQuestions] Attempting provider: ${provider} (${i + 1}/${providers.length})`);
9441
- logCollector?.info(`Generating questions with ${provider}...`);
9442
9018
  let result = [];
9443
9019
  if (provider === "groq") {
9444
9020
  logger.debug("[generateNextQuestions] Using Groq LLM for next questions");
@@ -9447,7 +9023,6 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
9447
9023
  component,
9448
9024
  componentData,
9449
9025
  groqApiKey,
9450
- logCollector,
9451
9026
  conversationHistory
9452
9027
  );
9453
9028
  } else if (provider === "gemini") {
@@ -9457,7 +9032,6 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
9457
9032
  component,
9458
9033
  componentData,
9459
9034
  geminiApiKey,
9460
- logCollector,
9461
9035
  conversationHistory
9462
9036
  );
9463
9037
  } else if (provider === "openai") {
@@ -9467,7 +9041,6 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
9467
9041
  component,
9468
9042
  componentData,
9469
9043
  openaiApiKey,
9470
- logCollector,
9471
9044
  conversationHistory
9472
9045
  );
9473
9046
  } else {
@@ -9477,44 +9050,32 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
9477
9050
  component,
9478
9051
  componentData,
9479
9052
  anthropicApiKey,
9480
- logCollector,
9481
9053
  conversationHistory
9482
9054
  );
9483
9055
  }
9484
9056
  if (result && result.length > 0) {
9485
9057
  logger.info(`[generateNextQuestions] Successfully generated ${result.length} questions with ${provider}`);
9486
9058
  logger.debug(`[generateNextQuestions] Questions: ${JSON.stringify(result)}`);
9487
- logCollector?.info(`Generated ${result.length} follow-up questions`);
9488
9059
  return result;
9489
9060
  }
9490
- const warnMsg = `No questions generated from ${provider}${!isLastProvider ? ", trying next provider..." : ""}`;
9491
- logger.warn(`[generateNextQuestions] ${warnMsg}`);
9492
- if (!isLastProvider) {
9493
- logCollector?.warn(warnMsg);
9494
- }
9061
+ logger.warn(`[generateNextQuestions] No questions generated from ${provider}${!isLastProvider ? ", trying next provider..." : ""}`);
9495
9062
  } catch (providerError) {
9496
9063
  const errorMsg = providerError instanceof Error ? providerError.message : String(providerError);
9497
9064
  logger.error(`[generateNextQuestions] Provider ${provider} failed: ${errorMsg}`);
9498
9065
  logger.debug(`[generateNextQuestions] Provider error details:`, providerError);
9499
9066
  if (!isLastProvider) {
9500
- const fallbackMsg = `Provider ${provider} failed, trying next provider...`;
9501
- logger.info(`[generateNextQuestions] ${fallbackMsg}`);
9502
- logCollector?.warn(fallbackMsg);
9503
- } else {
9504
- logCollector?.error(`Failed to generate questions with ${provider}`);
9067
+ logger.info(`[generateNextQuestions] Provider ${provider} failed, trying next provider...`);
9505
9068
  }
9506
9069
  continue;
9507
9070
  }
9508
9071
  }
9509
9072
  logger.warn("[generateNextQuestions] All providers failed or returned no questions");
9510
- logCollector?.warn("Unable to generate follow-up questions");
9511
9073
  return [];
9512
9074
  } catch (error) {
9513
9075
  const errorMsg = error instanceof Error ? error.message : String(error);
9514
9076
  const errorStack = error instanceof Error ? error.stack : void 0;
9515
9077
  logger.error(`[generateNextQuestions] Error generating next questions: ${errorMsg}`);
9516
9078
  logger.debug("[generateNextQuestions] Error stack trace:", errorStack);
9517
- logCollector?.error(`Error generating next questions: ${errorMsg}`);
9518
9079
  return [];
9519
9080
  }
9520
9081
  }
@@ -9562,9 +9123,6 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
9562
9123
  return;
9563
9124
  }
9564
9125
  logger.info(`[ACTIONS_REQ ${id}] UIBlock retrieved successfully`);
9565
- logger.debug(`[ACTIONS_REQ ${id}] Creating UILogCollector for uiBlockId: ${uiBlockId}`);
9566
- const logCollector = new UILogCollector(wsId, sendMessage, uiBlockId);
9567
- logger.info(`[ACTIONS_REQ ${id}] UILogCollector initialized`);
9568
9126
  logger.debug(`[ACTIONS_REQ ${id}] Extracting data from UIBlock`);
9569
9127
  const userQuestion = uiBlock.getUserQuestion();
9570
9128
  const component = uiBlock.getComponentMetadata();
@@ -9578,13 +9136,11 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
9578
9136
  logger.info(`[ACTIONS_REQ ${id}] Conversation history extracted: ${historyLineCount} lines`);
9579
9137
  logger.debug(`[ACTIONS_REQ ${id}] Conversation history preview:
9580
9138
  ${conversationHistory.substring(0, 200)}...`);
9581
- logCollector.info(`Generating actions for UIBlock: ${uiBlockId}`);
9582
- logger.info(`[ACTIONS_REQ ${id}] Generating actions for component: ${component?.name || "unknown"}`);
9139
+ logger.info(`[ACTIONS_REQ ${id}] Generating actions for UIBlock: ${uiBlockId}, component: ${component?.name || "unknown"}`);
9583
9140
  logger.debug(`[ACTIONS_REQ ${id}] Checking if actions are already cached`);
9584
9141
  const startTime = Date.now();
9585
9142
  const actions = await uiBlock.getOrFetchActions(async () => {
9586
9143
  logger.info(`[ACTIONS_REQ ${id}] Actions not cached, generating new actions...`);
9587
- logCollector.info("Generating follow-up questions...");
9588
9144
  logger.info(`[ACTIONS_REQ ${id}] Starting next questions generation with ${llmProviders?.join(", ") || "default"} providers`);
9589
9145
  const nextQuestions = await generateNextQuestions(
9590
9146
  userQuestion,
@@ -9595,7 +9151,6 @@ ${conversationHistory.substring(0, 200)}...`);
9595
9151
  geminiApiKey,
9596
9152
  openaiApiKey,
9597
9153
  llmProviders,
9598
- logCollector,
9599
9154
  conversationHistory
9600
9155
  );
9601
9156
  logger.info(`[ACTIONS_REQ ${id}] Generated ${nextQuestions.length} questions`);
@@ -9613,11 +9168,10 @@ ${conversationHistory.substring(0, 200)}...`);
9613
9168
  const processingTime = Date.now() - startTime;
9614
9169
  logger.info(`[ACTIONS_REQ ${id}] Actions retrieved in ${processingTime}ms - ${actions.length} actions total`);
9615
9170
  if (actions.length > 0) {
9616
- logCollector.info(`Generated ${actions.length} follow-up questions successfully`);
9171
+ logger.info(`[ACTIONS_REQ ${id}] Generated ${actions.length} follow-up questions successfully`);
9617
9172
  logger.debug(`[ACTIONS_REQ ${id}] Actions: ${actions.map((a) => a.name).join(", ")}`);
9618
9173
  } else {
9619
9174
  logger.warn(`[ACTIONS_REQ ${id}] No actions generated`);
9620
- logCollector.warn("No follow-up questions could be generated");
9621
9175
  }
9622
9176
  logger.debug(`[ACTIONS_REQ ${id}] Sending successful response to client`);
9623
9177
  sendResponse2(id, {
@@ -9636,15 +9190,6 @@ ${conversationHistory.substring(0, 200)}...`);
9636
9190
  const errorStack = error instanceof Error ? error.stack : void 0;
9637
9191
  logger.error(`[ACTIONS_REQ] Failed to handle actions request: ${errorMessage}`);
9638
9192
  logger.debug(`[ACTIONS_REQ] Error stack trace:`, errorStack);
9639
- try {
9640
- const parsedData = data;
9641
- if (parsedData?.id && parsedData?.from?.id) {
9642
- const logCollector = parsedData?.payload?.SA_RUNTIME?.uiBlockId ? new UILogCollector(parsedData.from.id, sendMessage, parsedData.payload.SA_RUNTIME.uiBlockId) : void 0;
9643
- logCollector?.error(`Failed to generate actions: ${errorMessage}`);
9644
- }
9645
- } catch (logError) {
9646
- logger.debug("[ACTIONS_REQ] Failed to send error logs to UI:", logError);
9647
- }
9648
9193
  sendResponse2(null, {
9649
9194
  success: false,
9650
9195
  error: errorMessage
@@ -10225,7 +9770,6 @@ function sendResponse3(id, res, sendMessage, clientId) {
10225
9770
  var dashboardManager = null;
10226
9771
  function setDashboardManager(manager) {
10227
9772
  dashboardManager = manager;
10228
- logger.info("DashboardManager instance set");
10229
9773
  }
10230
9774
  function getDashboardManager() {
10231
9775
  if (!dashboardManager) {
@@ -13552,6 +13096,190 @@ var ReportManager = class {
13552
13096
  }
13553
13097
  };
13554
13098
 
13099
+ // src/utils/log-collector.ts
13100
+ var LOG_LEVEL_PRIORITY2 = {
13101
+ errors: 0,
13102
+ warnings: 1,
13103
+ info: 2,
13104
+ verbose: 3
13105
+ };
13106
+ var MESSAGE_LEVEL_PRIORITY2 = {
13107
+ error: 0,
13108
+ warn: 1,
13109
+ info: 2,
13110
+ debug: 3
13111
+ };
13112
+ var UILogCollector = class {
13113
+ constructor(clientId, sendMessage, uiBlockId) {
13114
+ this.logs = [];
13115
+ this.uiBlockId = uiBlockId || null;
13116
+ this.clientId = clientId;
13117
+ this.sendMessage = sendMessage;
13118
+ this.currentLogLevel = logger.getLogLevel();
13119
+ }
13120
+ /**
13121
+ * Check if logging is enabled (uiBlockId is provided)
13122
+ */
13123
+ isEnabled() {
13124
+ return this.uiBlockId !== null;
13125
+ }
13126
+ /**
13127
+ * Check if a message should be logged based on current log level
13128
+ */
13129
+ shouldLog(messageLevel) {
13130
+ const currentLevelPriority = LOG_LEVEL_PRIORITY2[this.currentLogLevel];
13131
+ const messagePriority = MESSAGE_LEVEL_PRIORITY2[messageLevel];
13132
+ return messagePriority <= currentLevelPriority;
13133
+ }
13134
+ /**
13135
+ * Add a log entry with timestamp and immediately send to runtime
13136
+ * Only logs that pass the log level filter are captured and sent
13137
+ */
13138
+ addLog(level, message, type, data) {
13139
+ if (!this.shouldLog(level)) {
13140
+ return;
13141
+ }
13142
+ const log = {
13143
+ timestamp: Date.now(),
13144
+ level,
13145
+ message,
13146
+ ...type && { type },
13147
+ ...data && { data }
13148
+ };
13149
+ this.logs.push(log);
13150
+ this.sendLogImmediately(log);
13151
+ switch (level) {
13152
+ case "error":
13153
+ logger.error("UILogCollector:", log);
13154
+ break;
13155
+ case "warn":
13156
+ logger.warn("UILogCollector:", log);
13157
+ break;
13158
+ case "info":
13159
+ logger.info("UILogCollector:", log);
13160
+ break;
13161
+ case "debug":
13162
+ logger.debug("UILogCollector:", log);
13163
+ break;
13164
+ }
13165
+ }
13166
+ /**
13167
+ * Send a single log to runtime immediately
13168
+ */
13169
+ sendLogImmediately(log) {
13170
+ if (!this.isEnabled()) {
13171
+ return;
13172
+ }
13173
+ const response = {
13174
+ id: this.uiBlockId,
13175
+ type: "UI_LOGS",
13176
+ from: { type: "data-agent" },
13177
+ to: {
13178
+ type: "runtime",
13179
+ id: this.clientId
13180
+ },
13181
+ payload: {
13182
+ logs: [log]
13183
+ // Send single log in array
13184
+ }
13185
+ };
13186
+ this.sendMessage(response);
13187
+ }
13188
+ /**
13189
+ * Log info message
13190
+ */
13191
+ info(message, type, data) {
13192
+ if (this.isEnabled()) {
13193
+ this.addLog("info", message, type, data);
13194
+ }
13195
+ }
13196
+ /**
13197
+ * Log error message
13198
+ */
13199
+ error(message, type, data) {
13200
+ if (this.isEnabled()) {
13201
+ this.addLog("error", message, type, data);
13202
+ }
13203
+ }
13204
+ /**
13205
+ * Log warning message
13206
+ */
13207
+ warn(message, type, data) {
13208
+ if (this.isEnabled()) {
13209
+ this.addLog("warn", message, type, data);
13210
+ }
13211
+ }
13212
+ /**
13213
+ * Log debug message
13214
+ */
13215
+ debug(message, type, data) {
13216
+ if (this.isEnabled()) {
13217
+ this.addLog("debug", message, type, data);
13218
+ }
13219
+ }
13220
+ /**
13221
+ * Log LLM explanation with typed metadata
13222
+ */
13223
+ logExplanation(message, explanation, data) {
13224
+ if (this.isEnabled()) {
13225
+ this.addLog("info", message, "explanation", {
13226
+ explanation,
13227
+ ...data
13228
+ });
13229
+ }
13230
+ }
13231
+ /**
13232
+ * Log generated query with typed metadata
13233
+ */
13234
+ logQuery(message, query, data) {
13235
+ if (this.isEnabled()) {
13236
+ this.addLog("info", message, "query", {
13237
+ query,
13238
+ ...data
13239
+ });
13240
+ }
13241
+ }
13242
+ /**
13243
+ * Send all collected logs at once (optional, for final summary)
13244
+ */
13245
+ sendAllLogs() {
13246
+ if (!this.isEnabled() || this.logs.length === 0) {
13247
+ return;
13248
+ }
13249
+ const response = {
13250
+ id: this.uiBlockId,
13251
+ type: "UI_LOGS",
13252
+ from: { type: "data-agent" },
13253
+ to: {
13254
+ type: "runtime",
13255
+ id: this.clientId
13256
+ },
13257
+ payload: {
13258
+ logs: this.logs
13259
+ }
13260
+ };
13261
+ this.sendMessage(response);
13262
+ }
13263
+ /**
13264
+ * Get all collected logs
13265
+ */
13266
+ getLogs() {
13267
+ return [...this.logs];
13268
+ }
13269
+ /**
13270
+ * Clear all logs
13271
+ */
13272
+ clearLogs() {
13273
+ this.logs = [];
13274
+ }
13275
+ /**
13276
+ * Set uiBlockId (in case it's provided later)
13277
+ */
13278
+ setUIBlockId(uiBlockId) {
13279
+ this.uiBlockId = uiBlockId;
13280
+ }
13281
+ };
13282
+
13555
13283
  // src/services/cleanup-service.ts
13556
13284
  var CleanupService = class _CleanupService {
13557
13285
  constructor() {
@@ -13732,7 +13460,6 @@ var CleanupService = class _CleanupService {
13732
13460
  };
13733
13461
 
13734
13462
  // src/index.ts
13735
- var SDK_VERSION = "0.0.8";
13736
13463
  var DEFAULT_WS_URL = "wss://ws.superatom.ai/websocket";
13737
13464
  var SuperatomSDK = class {
13738
13465
  // 3.5 minutes (PING_INTERVAL + 30s grace)
@@ -13773,7 +13500,7 @@ var SuperatomSDK = class {
13773
13500
  if (config.queryCacheTTL !== void 0) {
13774
13501
  queryCache.setTTL(config.queryCacheTTL);
13775
13502
  }
13776
- logger.info(`Initializing Superatom SDK v${SDK_VERSION} for project ${this.projectId}, llm providers: ${this.llmProviders.join(", ")}, database type: ${this.databaseType}, model strategy: ${this.modelStrategy}, conversation similarity threshold: ${this.conversationSimilarityThreshold}, query cache TTL: ${queryCache.getTTL()} minutes`);
13503
+ logger.info(`Initializing Superatom SDK for project ${this.projectId}, llm providers: ${this.llmProviders.join(", ")}, database type: ${this.databaseType}, model strategy: ${this.modelStrategy}, query cache TTL: ${queryCache.getTTL()} minutes`);
13777
13504
  this.userManager = new UserManager(this.projectId, 5e3);
13778
13505
  this.dashboardManager = new DashboardManager(this.projectId);
13779
13506
  this.reportManager = new ReportManager(this.projectId);
@@ -13827,7 +13554,6 @@ var SuperatomSDK = class {
13827
13554
  */
13828
13555
  initializeDashboardManager() {
13829
13556
  setDashboardManager(this.dashboardManager);
13830
- logger.info(`DashboardManager initialized for project: ${this.projectId}`);
13831
13557
  }
13832
13558
  /**
13833
13559
  * Get the DashboardManager instance for this SDK
@@ -13840,7 +13566,6 @@ var SuperatomSDK = class {
13840
13566
  */
13841
13567
  initializeReportManager() {
13842
13568
  setReportManager(this.reportManager);
13843
- logger.info(`ReportManager initialized for project: ${this.projectId}`);
13844
13569
  }
13845
13570
  /**
13846
13571
  * Get the ReportManager instance for this SDK
@@ -14217,7 +13942,6 @@ export {
14217
13942
  CONTEXT_CONFIG,
14218
13943
  CleanupService,
14219
13944
  LLM,
14220
- SDK_VERSION,
14221
13945
  STORAGE_CONFIG,
14222
13946
  SuperatomSDK,
14223
13947
  Thread,