@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.js CHANGED
@@ -34,7 +34,6 @@ __export(index_exports, {
34
34
  CONTEXT_CONFIG: () => CONTEXT_CONFIG,
35
35
  CleanupService: () => CleanupService,
36
36
  LLM: () => LLM,
37
- SDK_VERSION: () => SDK_VERSION,
38
37
  STORAGE_CONFIG: () => STORAGE_CONFIG,
39
38
  SuperatomSDK: () => SuperatomSDK,
40
39
  Thread: () => Thread,
@@ -3368,24 +3367,20 @@ If adaptation is not possible or would fundamentally change the component:
3368
3367
  "dash-comp-picker": {
3369
3368
  system: `You are a component selection expert that picks the best dashboard component and generates complete props based on user requests.
3370
3369
 
3370
+ ## CRITICAL - READ FIRST
3371
+
3372
+ 1. Your ENTIRE response must be ONLY a raw JSON object - start with { end with }
3373
+ 2. DO NOT explain or answer the user's question in natural language
3374
+ 3. DO NOT use markdown code blocks (no \`\`\`)
3375
+ 4. DO NOT add any text before or after the JSON
3376
+ 5. After executing tools (if needed), return JSON with component selection - NOT a text summary of results
3377
+
3371
3378
  ## Your Task
3372
3379
 
3373
3380
  Analyze the user's request and:
3374
3381
  1. **Select the most appropriate component** from the available components list
3375
- 2. **Determine the data source**: Database query OR External tool
3376
- 3. **Generate complete props** for the selected component
3377
-
3378
- ## Available External Tools
3379
-
3380
- The following external tools are available:
3381
-
3382
- {{AVAILABLE_TOOLS}}
3383
-
3384
- When a tool is needed to complete the user's request:
3385
- 1. **Analyze the request** to determine which tool is needed
3386
- 2. **Extract parameters** from the user's question
3387
- 3. **Execute the tool** by calling it with the extracted parameters
3388
- 4. **Use the results** to configure the component (field names for axes, columns, etc.)
3382
+ 2. **Determine the data source**: Database query OR External tool (ERP)
3383
+ 3. **Generate complete props** for the selected component including the data retrieval/modification method
3389
3384
 
3390
3385
  ## Component Selection Rules
3391
3386
 
@@ -3415,7 +3410,7 @@ The user prompt may contain an **existing component** to update. Detect this by
3415
3410
 
3416
3411
  ### Use DATABASE when:
3417
3412
  - User asks about data that exists in the database schema
3418
- - Questions about internal business data
3413
+ - Questions about internal business data
3419
3414
  - CRUD operations on database tables
3420
3415
 
3421
3416
  ### Use EXTERNAL TOOL when:
@@ -3428,6 +3423,12 @@ The user prompt may contain an **existing component** to update. Detect this by
3428
3423
 
3429
3424
  **CRITICAL**: Look at each component's "Props Structure" in the available components list. Generate ALL props that the component expects.
3430
3425
 
3426
+ **CRITICAL: Each component uses EXACTLY ONE data source - never both!**
3427
+ - If using \`query\`, set \`externalTool: null\`
3428
+ - If using \`externalTool\`, set \`query: null\`
3429
+ - NEVER copy placeholder/description text from component metadata as actual values
3430
+ - \`externalTool.parameters\` MUST be an object, never a string
3431
+
3431
3432
  ### For Data Viewing Components (charts, tables, KPIs):
3432
3433
 
3433
3434
  **Option A: Database Query** (when data is in database)
@@ -3436,21 +3437,19 @@ The user prompt may contain an **existing component** to update. Detect this by
3436
3437
  "query": {
3437
3438
  "sql": "SELECT column1, column2 FROM table WHERE condition = $param LIMIT 32",
3438
3439
  "params": { "param": "value" }
3439
- }
3440
+ },
3441
+ "externalTool": null
3440
3442
  }
3441
3443
  \`\`\`
3442
3444
 
3443
3445
  **Option B: External Tool** (when data is from ERP/external system)
3444
3446
  \`\`\`json
3445
3447
  {
3448
+ "query": null,
3446
3449
  "externalTool": {
3447
3450
  "toolId": "tool_id_from_list",
3448
3451
  "toolName": "Tool Display Name",
3449
- "action": "get",
3450
- "params": {
3451
- "param1": "value1",
3452
- "param2": "value2"
3453
- }
3452
+ "parameters": { "param1": "value1", "param2": "value2" }
3454
3453
  }
3455
3454
  }
3456
3455
  \`\`\`
@@ -3464,6 +3463,7 @@ The user prompt may contain an **existing component** to update. Detect this by
3464
3463
  "sql": "INSERT INTO table (col1, col2) VALUES ($col1, $col2)",
3465
3464
  "params": {}
3466
3465
  },
3466
+ "externalTool": null,
3467
3467
  "fields": [
3468
3468
  { "name": "col1", "type": "text", "required": true },
3469
3469
  { "name": "col2", "type": "number", "required": false }
@@ -3471,16 +3471,38 @@ The user prompt may contain an **existing component** to update. Detect this by
3471
3471
  }
3472
3472
  \`\`\`
3473
3473
 
3474
+ For UPDATE:
3475
+ \`\`\`json
3476
+ {
3477
+ "query": {
3478
+ "sql": "UPDATE table SET col1 = $col1, col2 = $col2 WHERE id = $id",
3479
+ "params": { "id": "record_id" }
3480
+ },
3481
+ "externalTool": null
3482
+ }
3483
+ \`\`\`
3484
+
3485
+ For DELETE:
3486
+ \`\`\`json
3487
+ {
3488
+ "query": {
3489
+ "sql": "DELETE FROM table WHERE id = $id",
3490
+ "params": { "id": "record_id" }
3491
+ },
3492
+ "externalTool": null,
3493
+ "submitButtonText": "Confirm Delete",
3494
+ "submitButtonColor": "danger"
3495
+ }
3496
+ \`\`\`
3497
+
3474
3498
  **Option B: External Tool Mutation**
3475
3499
  \`\`\`json
3476
3500
  {
3501
+ "query": null,
3477
3502
  "externalTool": {
3478
3503
  "toolId": "tool_id_from_list",
3479
3504
  "toolName": "Tool Display Name",
3480
- "action": "create|update|delete",
3481
- "params": {
3482
- "param1": "value_or_placeholder"
3483
- }
3505
+ "parameters": { "param1": "value_or_placeholder" }
3484
3506
  },
3485
3507
  "fields": [
3486
3508
  { "name": "param1", "type": "text", "required": true }
@@ -3495,6 +3517,7 @@ The user prompt may contain an **existing component** to update. Detect this by
3495
3517
 
3496
3518
  You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
3497
3519
 
3520
+ \`\`\`json
3498
3521
  {
3499
3522
  "componentId": "id_from_available_list_or_existing_component_id",
3500
3523
  "componentName": "name_of_component",
@@ -3509,6 +3532,7 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
3509
3532
  // Include all other required props (title, description, config, fields, etc.)
3510
3533
  }
3511
3534
  }
3535
+ \`\`\`
3512
3536
 
3513
3537
  **CRITICAL:**
3514
3538
  - Return ONLY valid JSON (no markdown code blocks, no text before/after)
@@ -3531,7 +3555,8 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
3531
3555
 
3532
3556
  ---
3533
3557
 
3534
- ## CONTEXT`,
3558
+ ## CONTEXT
3559
+ `,
3535
3560
  user: `{{USER_PROMPT}}`
3536
3561
  },
3537
3562
  "dash-filter-picker": {
@@ -3677,9 +3702,7 @@ var PromptLoader = class {
3677
3702
  this.databaseRulesCache = /* @__PURE__ */ new Map();
3678
3703
  this.isInitialized = false;
3679
3704
  this.databaseType = "postgresql";
3680
- logger.debug("Initializing PromptLoader...");
3681
3705
  this.promptsDir = config?.promptsDir || import_path.default.join(process.cwd(), ".prompts");
3682
- logger.debug(`Prompts directory set to: ${this.promptsDir}`);
3683
3706
  }
3684
3707
  /**
3685
3708
  * Load a prompt template from file system OR fallback to hardcoded prompts
@@ -3693,7 +3716,6 @@ var PromptLoader = class {
3693
3716
  if (import_fs2.default.existsSync(systemPath) && import_fs2.default.existsSync(userPath)) {
3694
3717
  const system = import_fs2.default.readFileSync(systemPath, "utf-8");
3695
3718
  const user = import_fs2.default.readFileSync(userPath, "utf-8");
3696
- logger.info(`\u2713 Loaded prompt '${promptName}' from file system: ${this.promptsDir}`);
3697
3719
  return { system, user };
3698
3720
  }
3699
3721
  } catch (error) {
@@ -3701,7 +3723,6 @@ var PromptLoader = class {
3701
3723
  }
3702
3724
  const hardcodedPrompt = PROMPTS[promptName];
3703
3725
  if (hardcodedPrompt) {
3704
- logger.info(`\u2713 Loaded prompt '${promptName}' from hardcoded fallback`);
3705
3726
  return hardcodedPrompt;
3706
3727
  }
3707
3728
  throw new Error(`Prompt template '${promptName}' not found in either ${this.promptsDir} or hardcoded prompts. Available prompts: ${Object.keys(PROMPTS).join(", ")}`);
@@ -3715,7 +3736,6 @@ var PromptLoader = class {
3715
3736
  logger.debug("PromptLoader already initialized, skipping...");
3716
3737
  return;
3717
3738
  }
3718
- logger.info("Loading prompts into memory...");
3719
3739
  const promptTypes = Object.keys(PROMPTS);
3720
3740
  for (const promptName of promptTypes) {
3721
3741
  try {
@@ -3727,7 +3747,6 @@ var PromptLoader = class {
3727
3747
  }
3728
3748
  }
3729
3749
  this.isInitialized = true;
3730
- logger.info(`Successfully loaded ${this.promptCache.size} prompt templates into memory`);
3731
3750
  }
3732
3751
  /**
3733
3752
  * Replace variables in a template string using {{VARIABLE_NAME}} pattern
@@ -3767,7 +3786,6 @@ var PromptLoader = class {
3767
3786
  const processedContext = this.replaceVariables(contextMarker + contextPart, variables);
3768
3787
  const staticLength = processedStatic.length;
3769
3788
  const contextLength = processedContext.length;
3770
- logger.debug(`\u2713 Prompt caching enabled for '${promptName}' (cached: ${staticLength} chars, dynamic: ${contextLength} chars)`);
3771
3789
  return {
3772
3790
  system: [
3773
3791
  {
@@ -3804,7 +3822,6 @@ var PromptLoader = class {
3804
3822
  this.promptsDir = dir;
3805
3823
  this.isInitialized = false;
3806
3824
  this.promptCache.clear();
3807
- logger.debug(`Prompts directory changed to: ${dir}`);
3808
3825
  }
3809
3826
  /**
3810
3827
  * Get current prompts directory
@@ -3832,7 +3849,6 @@ var PromptLoader = class {
3832
3849
  setDatabaseType(type) {
3833
3850
  this.databaseType = type;
3834
3851
  this.databaseRulesCache.clear();
3835
- logger.debug(`Database type set to: ${type}`);
3836
3852
  }
3837
3853
  /**
3838
3854
  * Get current database type
@@ -3848,7 +3864,6 @@ var PromptLoader = class {
3848
3864
  */
3849
3865
  async loadDatabaseRules() {
3850
3866
  if (this.databaseRulesCache.has(this.databaseType)) {
3851
- logger.debug(`\u2713 Database rules for '${this.databaseType}' loaded from cache`);
3852
3867
  return this.databaseRulesCache.get(this.databaseType);
3853
3868
  }
3854
3869
  const rulesPath = import_path.default.join(this.promptsDir, "database-rules", `${this.databaseType}.md`);
@@ -3856,7 +3871,6 @@ var PromptLoader = class {
3856
3871
  if (import_fs2.default.existsSync(rulesPath)) {
3857
3872
  const rules = import_fs2.default.readFileSync(rulesPath, "utf-8");
3858
3873
  this.databaseRulesCache.set(this.databaseType, rules);
3859
- logger.info(`\u2713 Loaded database rules for '${this.databaseType}' from ${rulesPath}`);
3860
3874
  return rules;
3861
3875
  }
3862
3876
  } catch (error) {
@@ -4132,7 +4146,6 @@ var Schema = class {
4132
4146
  * @returns Parsed schema object or null if error occurs
4133
4147
  */
4134
4148
  getDatabaseSchema() {
4135
- logger.info(`SCHEMA_FILE_PATH: ${this.schemaFilePath}`);
4136
4149
  try {
4137
4150
  const dir = import_path2.default.dirname(this.schemaFilePath);
4138
4151
  if (!import_fs3.default.existsSync(dir)) {
@@ -4401,14 +4414,6 @@ Format: [TIMESTAMP] [REQUEST_ID] [PROVIDER/MODEL] [METHOD]
4401
4414
  Cost: $${entry.costUSD.toFixed(6)} | Time: ${entry.durationMs}ms${toolInfo}${errorInfo}${cacheStatus}
4402
4415
  `;
4403
4416
  this.logStream?.write(logLine);
4404
- if (entry.cacheReadTokens && entry.cacheReadTokens > 0) {
4405
- console.log(`[LLM] \u26A1 CACHE HIT: ${entry.cacheReadTokens.toLocaleString()} tokens read from cache (${entry.method})`);
4406
- } else if (entry.cacheWriteTokens && entry.cacheWriteTokens > 0) {
4407
- console.log(`[LLM] \u{1F4DD} CACHE WRITE: ${entry.cacheWriteTokens.toLocaleString()} tokens cached for future requests (${entry.method})`);
4408
- }
4409
- if (process.env.SUPERATOM_LOG_LEVEL === "verbose") {
4410
- console.log("\n[LLM-Usage]", logLine);
4411
- }
4412
4417
  }
4413
4418
  /**
4414
4419
  * Log session summary (call at end of request)
@@ -4441,11 +4446,6 @@ Avg Time/Call: ${Math.round(this.sessionStats.totalDurationMs / this.sessionStat
4441
4446
 
4442
4447
  `;
4443
4448
  this.logStream?.write(summary);
4444
- console.log("\n[LLM-Usage] Session Summary:");
4445
- 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`);
4446
- if (hasCaching) {
4447
- console.log(` Cache: ${this.sessionStats.totalCacheReadTokens.toLocaleString()} read, ${this.sessionStats.totalCacheWriteTokens.toLocaleString()} written | Savings: ~$${cacheReadSavings.toFixed(4)}`);
4448
- }
4449
4449
  }
4450
4450
  /**
4451
4451
  * Reset session stats (call at start of new user request)
@@ -4486,7 +4486,6 @@ Format: [TIMESTAMP] [REQUEST_ID] [PROVIDER/MODEL] [METHOD]
4486
4486
  `;
4487
4487
  this.logStream.write(header);
4488
4488
  this.resetSession();
4489
- console.log(`[LLM-Usage] Log file reset for new request: ${this.logPath}`);
4490
4489
  } catch (error) {
4491
4490
  console.error("[LLM-Usage-Logger] Failed to reset log file:", error);
4492
4491
  }
@@ -5960,21 +5959,20 @@ var getKnowledgeBase = async ({
5960
5959
  }) => {
5961
5960
  try {
5962
5961
  if (!collections || !collections["knowledge-base"] || !collections["knowledge-base"]["query"]) {
5963
- logger.info("[KnowledgeBase] knowledge-base.query collection not registered, skipping");
5962
+ logger.warn("[KnowledgeBase] knowledge-base.query collection not registered, skipping");
5964
5963
  return "";
5965
5964
  }
5966
- logger.info(`[KnowledgeBase] Querying knowledge base for: "${prompt.substring(0, 50)}..."`);
5967
5965
  const result = await collections["knowledge-base"]["query"]({
5968
5966
  prompt,
5969
5967
  topK
5970
5968
  });
5971
5969
  if (!result || !result.content) {
5972
- logger.info("[KnowledgeBase] No knowledge base results returned");
5970
+ logger.warn("[KnowledgeBase] No knowledge base results returned");
5973
5971
  return "";
5974
5972
  }
5975
5973
  logger.info(`[KnowledgeBase] Retrieved knowledge base context (${result.content.length} chars)`);
5976
5974
  if (result.metadata?.sources && result.metadata.sources.length > 0) {
5977
- logger.debug(`[KnowledgeBase] Sources: ${result.metadata.sources.map((s) => s.title).join(", ")}`);
5975
+ logger.warn(`[KnowledgeBase] Sources: ${result.metadata.sources.map((s) => s.title).join(", ")}`);
5978
5976
  }
5979
5977
  return result.content;
5980
5978
  } catch (error) {
@@ -5989,13 +5987,12 @@ var getGlobalKnowledgeBase = async ({
5989
5987
  }) => {
5990
5988
  try {
5991
5989
  if (!collections || !collections["knowledge-base"] || !collections["knowledge-base"]["getGlobal"]) {
5992
- logger.info("[KnowledgeBase] knowledge-base.getGlobal collection not registered, skipping");
5990
+ logger.warn("[KnowledgeBase] knowledge-base.getGlobal collection not registered, skipping");
5993
5991
  return "";
5994
5992
  }
5995
- logger.info("[KnowledgeBase] Fetching global knowledge base nodes...");
5996
5993
  const result = await collections["knowledge-base"]["getGlobal"]({ limit });
5997
5994
  if (!result || !result.content) {
5998
- logger.info("[KnowledgeBase] No global knowledge base nodes found");
5995
+ logger.warn("[KnowledgeBase] No global knowledge base nodes found");
5999
5996
  return "";
6000
5997
  }
6001
5998
  logger.info(`[KnowledgeBase] Retrieved ${result.count || 0} global knowledge base nodes`);
@@ -6013,14 +6010,13 @@ var getUserKnowledgeBase = async ({
6013
6010
  }) => {
6014
6011
  try {
6015
6012
  if (!userId) {
6016
- logger.info("[KnowledgeBase] No userId provided, skipping user knowledge base");
6013
+ logger.warn("[KnowledgeBase] No userId provided, skipping user knowledge base");
6017
6014
  return "";
6018
6015
  }
6019
6016
  if (!collections || !collections["knowledge-base"] || !collections["knowledge-base"]["getByUser"]) {
6020
- logger.info("[KnowledgeBase] knowledge-base.getByUser collection not registered, skipping");
6017
+ logger.warn("[KnowledgeBase] knowledge-base.getByUser collection not registered, skipping");
6021
6018
  return "";
6022
6019
  }
6023
- logger.info(`[KnowledgeBase] Fetching user knowledge base nodes for userId: ${userId}...`);
6024
6020
  const result = await collections["knowledge-base"]["getByUser"]({
6025
6021
  userId: Number(userId),
6026
6022
  limit
@@ -6043,7 +6039,6 @@ var getAllKnowledgeBase = async ({
6043
6039
  userId,
6044
6040
  topK = 3
6045
6041
  }) => {
6046
- logger.info("[KnowledgeBase] Fetching all knowledge base contexts...");
6047
6042
  const [globalContext, userContext, queryContext] = await Promise.all([
6048
6043
  getGlobalKnowledgeBase({ collections }),
6049
6044
  getUserKnowledgeBase({ collections, userId }),
@@ -6065,7 +6060,6 @@ var getAllKnowledgeBase = async ({
6065
6060
  combinedContext += "The following information is semantically relevant to the current query:\n\n";
6066
6061
  combinedContext += queryContext + "\n\n";
6067
6062
  }
6068
- logger.info(`[KnowledgeBase] Combined knowledge base context: global=${globalContext.length} chars, user=${userContext.length} chars, query=${queryContext.length} chars`);
6069
6063
  return {
6070
6064
  globalContext,
6071
6065
  userContext,
@@ -6302,11 +6296,11 @@ var searchConversationsWithReranking = async (options) => {
6302
6296
  } = options;
6303
6297
  try {
6304
6298
  if (!collections || !collections["conversation-history"]) {
6305
- logger.info("[ConversationSearch] conversation-history collection not registered, skipping");
6299
+ logger.warn("[ConversationSearch] conversation-history collection not registered, skipping");
6306
6300
  return null;
6307
6301
  }
6308
6302
  if (!collections["conversation-history"]["searchMultiple"]) {
6309
- logger.info("[ConversationSearch] searchMultiple not available, falling back to standard search");
6303
+ logger.warn("[ConversationSearch] searchMultiple not available, falling back to standard search");
6310
6304
  return searchConversations({
6311
6305
  userPrompt,
6312
6306
  collections,
@@ -6314,9 +6308,6 @@ var searchConversationsWithReranking = async (options) => {
6314
6308
  similarityThreshold
6315
6309
  });
6316
6310
  }
6317
- logger.info(`[ConversationSearch] Hybrid search for: "${userPrompt.substring(0, 50)}..."`);
6318
- logger.info(`[ConversationSearch] Fetching ${rerankCandidates} candidates for reranking`);
6319
- logger.info(`[ConversationSearch] Weights - Semantic: ${hybridOptions.semanticWeight}, BM25: ${hybridOptions.bm25Weight}`);
6320
6311
  const results = await collections["conversation-history"]["searchMultiple"]({
6321
6312
  userPrompt,
6322
6313
  userId,
@@ -6357,7 +6348,6 @@ var searchConversationsWithReranking = async (options) => {
6357
6348
  logger.info(
6358
6349
  `[ConversationSearch] \u2713 Found match with semantic score ${(semanticScore * 100).toFixed(2)}%`
6359
6350
  );
6360
- logger.info(` - Returning cached result for: "${matchedUserPrompt}"`);
6361
6351
  return {
6362
6352
  uiBlock: best.uiBlock,
6363
6353
  similarity: semanticScore,
@@ -6799,10 +6789,9 @@ Fixed SQL query:`;
6799
6789
  * @param component - The component to validate
6800
6790
  * @param collections - Collections object containing database execute function
6801
6791
  * @param apiKey - Optional API key for LLM calls
6802
- * @param logCollector - Optional log collector for logging
6803
6792
  * @returns Validation result with component, query key, and result
6804
6793
  */
6805
- async validateSingleQuery(component, collections, apiKey, logCollector) {
6794
+ async validateSingleQuery(component, collections, apiKey) {
6806
6795
  const query = component.props?.query;
6807
6796
  const originalQueryKey = this.getQueryCacheKey(query);
6808
6797
  const queryStr = typeof query === "string" ? query : query?.sql || "";
@@ -6823,7 +6812,6 @@ Fixed SQL query:`;
6823
6812
  validated = true;
6824
6813
  queryCache.set(validationResult.cacheKey, result);
6825
6814
  logger.info(`[${this.config.providerName}] \u2713 Query validated for ${component.name} (attempt ${attempts}) - cached for frontend`);
6826
- logCollector?.info(`\u2713 Query validated for ${component.name}`);
6827
6815
  if (currentQueryStr !== queryStr) {
6828
6816
  const fixedQuery = typeof query === "string" ? currentQueryStr : { ...query, sql: currentQueryStr };
6829
6817
  component.props = {
@@ -6836,14 +6824,11 @@ Fixed SQL query:`;
6836
6824
  } catch (error) {
6837
6825
  lastError = error instanceof Error ? error.message : String(error);
6838
6826
  logger.warn(`[${this.config.providerName}] Query validation failed for ${component.name} (attempt ${attempts}/${MAX_QUERY_VALIDATION_RETRIES}): ${lastError}`);
6839
- logCollector?.warn(`Query validation failed for ${component.name}: ${lastError}`);
6840
6827
  if (attempts >= MAX_QUERY_VALIDATION_RETRIES) {
6841
6828
  logger.error(`[${this.config.providerName}] \u2717 Max retries reached for ${component.name}, excluding from response`);
6842
- logCollector?.error(`Max retries reached for ${component.name}, component excluded from response`);
6843
6829
  break;
6844
6830
  }
6845
6831
  logger.info(`[${this.config.providerName}] Requesting query fix from LLM for ${component.name}...`);
6846
- logCollector?.info(`Requesting query fix for ${component.name}...`);
6847
6832
  try {
6848
6833
  const fixedQueryStr = await this.requestQueryFix(
6849
6834
  currentQueryStr,
@@ -6877,7 +6862,6 @@ Fixed SQL query:`;
6877
6862
  }
6878
6863
  if (!validated) {
6879
6864
  logger.warn(`[${this.config.providerName}] Component ${component.name} excluded from response due to failed query validation`);
6880
- logCollector?.warn(`Component ${component.name} excluded from response`);
6881
6865
  }
6882
6866
  return {
6883
6867
  component: validated ? component : null,
@@ -6891,10 +6875,9 @@ Fixed SQL query:`;
6891
6875
  * @param components - Array of components with potential queries
6892
6876
  * @param collections - Collections object containing database execute function
6893
6877
  * @param apiKey - Optional API key for LLM calls
6894
- * @param logCollector - Optional log collector for logging
6895
6878
  * @returns Object with validated components and query results map
6896
6879
  */
6897
- async validateComponentQueries(components, collections, apiKey, logCollector) {
6880
+ async validateComponentQueries(components, collections, apiKey) {
6898
6881
  const queryResults = /* @__PURE__ */ new Map();
6899
6882
  const validatedComponents = [];
6900
6883
  const componentsWithoutQuery = [];
@@ -6911,9 +6894,8 @@ Fixed SQL query:`;
6911
6894
  return { components: validatedComponents, queryResults };
6912
6895
  }
6913
6896
  logger.info(`[${this.config.providerName}] Validating ${componentsWithQuery.length} component queries in parallel...`);
6914
- logCollector?.info(`Validating ${componentsWithQuery.length} component queries in parallel...`);
6915
6897
  const validationPromises = componentsWithQuery.map(
6916
- (component) => this.validateSingleQuery(component, collections, apiKey, logCollector)
6898
+ (component) => this.validateSingleQuery(component, collections, apiKey)
6917
6899
  );
6918
6900
  const results = await Promise.allSettled(validationPromises);
6919
6901
  for (let i = 0; i < results.length; i++) {
@@ -6930,7 +6912,6 @@ Fixed SQL query:`;
6930
6912
  }
6931
6913
  } else {
6932
6914
  logger.error(`[${this.config.providerName}] Unexpected error validating ${component.name}: ${result.reason}`);
6933
- logCollector?.error(`Unexpected error validating ${component.name}: ${result.reason}`);
6934
6915
  }
6935
6916
  }
6936
6917
  logger.info(`[${this.config.providerName}] Parallel validation complete: ${validatedComponents.length}/${components.length} components validated`);
@@ -6992,22 +6973,17 @@ var ToolExecutorService = class {
6992
6973
  let sql = toolInput.sql;
6993
6974
  const params = toolInput.params || {};
6994
6975
  const reasoning = toolInput.reasoning;
6995
- const { streamBuffer, collections, logCollector, providerName } = this.config;
6976
+ const { streamBuffer, collections, providerName } = this.config;
6996
6977
  sql = ensureQueryLimit(sql, MAX_COMPONENT_QUERY_LIMIT, MAX_COMPONENT_QUERY_LIMIT);
6997
6978
  const queryKey = sql.toLowerCase().replace(/\s+/g, " ").trim();
6998
6979
  const attempts = (this.queryAttempts.get(queryKey) || 0) + 1;
6999
6980
  this.queryAttempts.set(queryKey, attempts);
7000
- logger.info(`[${providerName}] Executing query (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${sql.substring(0, 100)}...`);
7001
6981
  if (Object.keys(params).length > 0) {
7002
6982
  logger.info(`[${providerName}] Query params: ${JSON.stringify(params)}`);
7003
6983
  }
7004
- if (reasoning) {
7005
- logCollector?.info(`Query reasoning: ${reasoning}`);
7006
- }
7007
6984
  if (attempts > MAX_QUERY_ATTEMPTS) {
7008
6985
  const errorMsg = `Maximum query attempts (${MAX_QUERY_ATTEMPTS}) reached. Unable to generate a valid query for your question.`;
7009
6986
  logger.error(`[${providerName}] ${errorMsg}`);
7010
- logCollector?.error(errorMsg);
7011
6987
  this.maxAttemptsReached = true;
7012
6988
  if (streamBuffer.hasCallback()) {
7013
6989
  streamBuffer.write(`
@@ -7067,11 +7043,6 @@ ${sql}
7067
7043
  await streamDelay();
7068
7044
  }
7069
7045
  }
7070
- logCollector?.logQuery?.(
7071
- `Executing SQL query (attempt ${attempts})`,
7072
- { sql, params },
7073
- { reasoning, attempt: attempts }
7074
- );
7075
7046
  if (!collections?.["database"]?.["execute"]) {
7076
7047
  throw new Error("Database collection not registered. Please register database.execute collection to execute queries.");
7077
7048
  }
@@ -7083,8 +7054,6 @@ ${sql}
7083
7054
  );
7084
7055
  const data = result?.data || result;
7085
7056
  const rowCount = result?.count ?? (Array.isArray(data) ? data.length : "N/A");
7086
- logger.info(`[${providerName}] Query executed successfully, rows returned: ${rowCount}`);
7087
- logCollector?.info(`Query successful, returned ${rowCount} rows`);
7088
7057
  if (streamBuffer.hasCallback()) {
7089
7058
  streamBuffer.write(`
7090
7059
  \u2705 **Query executed successfully!**
@@ -7133,7 +7102,6 @@ ${sql}
7133
7102
  maxRows: DEFAULT_MAX_ROWS_FOR_LLM,
7134
7103
  maxCharsPerField: DEFAULT_MAX_CHARS_PER_FIELD2
7135
7104
  });
7136
- logger.info(`[${providerName}] Query result formatted: ${formattedResult.summary.recordsShown}/${formattedResult.summary.totalRecords} records`);
7137
7105
  if (formattedResult.truncationNote) {
7138
7106
  logger.info(`[${providerName}] Truncation: ${formattedResult.truncationNote}`);
7139
7107
  }
@@ -7141,7 +7109,6 @@ ${sql}
7141
7109
  } catch (error) {
7142
7110
  const errorMsg = error instanceof Error ? error.message : String(error);
7143
7111
  logger.error(`[${providerName}] Query execution failed (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${errorMsg}`);
7144
- logCollector?.error(`Query failed (attempt ${attempts}/${MAX_QUERY_ATTEMPTS}): ${errorMsg}`);
7145
7112
  userPromptErrorLogger.logSqlError(sql, error instanceof Error ? error : new Error(errorMsg), Object.keys(params).length > 0 ? Object.values(params) : void 0);
7146
7113
  if (streamBuffer.hasCallback()) {
7147
7114
  streamBuffer.write(`\u274C **Query execution failed:**
@@ -7163,19 +7130,16 @@ ${errorMsg}
7163
7130
  * Execute an external tool with retry tracking and streaming feedback
7164
7131
  */
7165
7132
  async executeExternalTool(toolName, toolInput, externalTools) {
7166
- const { streamBuffer, logCollector, providerName } = this.config;
7133
+ const { streamBuffer, providerName } = this.config;
7167
7134
  const externalTool = externalTools?.find((t) => t.id === toolName);
7168
7135
  if (!externalTool) {
7169
7136
  throw new Error(`Unknown tool: ${toolName}`);
7170
7137
  }
7171
7138
  const attempts = (this.toolAttempts.get(toolName) || 0) + 1;
7172
7139
  this.toolAttempts.set(toolName, attempts);
7173
- logger.info(`[${providerName}] Executing external tool: ${externalTool.name} (attempt ${attempts}/${MAX_TOOL_ATTEMPTS})`);
7174
- logCollector?.info(`Executing external tool: ${externalTool.name} (attempt ${attempts}/${MAX_TOOL_ATTEMPTS})...`);
7175
7140
  if (attempts > MAX_TOOL_ATTEMPTS) {
7176
7141
  const errorMsg = `Maximum attempts (${MAX_TOOL_ATTEMPTS}) reached for tool: ${externalTool.name}`;
7177
7142
  logger.error(`[${providerName}] ${errorMsg}`);
7178
- logCollector?.error(errorMsg);
7179
7143
  if (streamBuffer.hasCallback()) {
7180
7144
  streamBuffer.write(`
7181
7145
 
@@ -7210,8 +7174,6 @@ Please try rephrasing your request or contact support.
7210
7174
  `Running ${externalTool.name}`,
7211
7175
  streamBuffer
7212
7176
  );
7213
- logger.info(`[${providerName}] External tool ${externalTool.name} executed successfully`);
7214
- logCollector?.info(`\u2713 ${externalTool.name} executed successfully`);
7215
7177
  if (!this.executedToolsList.find((t) => t.id === externalTool.id)) {
7216
7178
  const formattedForTracking = formatToolResultForLLM(result, {
7217
7179
  toolName: externalTool.name,
@@ -7231,7 +7193,6 @@ Please try rephrasing your request or contact support.
7231
7193
  },
7232
7194
  outputSchema: externalTool.outputSchema
7233
7195
  });
7234
- logger.info(`[${providerName}] Tracked executed tool: ${externalTool.name} with ${formattedForTracking.summary.totalRecords} total records`);
7235
7196
  }
7236
7197
  if (streamBuffer.hasCallback()) {
7237
7198
  streamBuffer.write(`\u2705 **${externalTool.name} completed successfully**
@@ -7245,7 +7206,6 @@ Please try rephrasing your request or contact support.
7245
7206
  maxRows: DEFAULT_MAX_ROWS_FOR_LLM,
7246
7207
  maxCharsPerField: DEFAULT_MAX_CHARS_PER_FIELD2
7247
7208
  });
7248
- logger.info(`[${providerName}] Tool result formatted: ${formattedToolResult.summary.recordsShown}/${formattedToolResult.summary.totalRecords} records`);
7249
7209
  if (formattedToolResult.truncationNote) {
7250
7210
  logger.info(`[${providerName}] Truncation: ${formattedToolResult.truncationNote}`);
7251
7211
  }
@@ -7253,7 +7213,6 @@ Please try rephrasing your request or contact support.
7253
7213
  } catch (error) {
7254
7214
  const errorMsg = error instanceof Error ? error.message : String(error);
7255
7215
  logger.error(`[${providerName}] External tool ${externalTool.name} failed (attempt ${attempts}/${MAX_TOOL_ATTEMPTS}): ${errorMsg}`);
7256
- logCollector?.error(`\u2717 ${externalTool.name} failed: ${errorMsg}`);
7257
7216
  userPromptErrorLogger.logToolError(externalTool.name, toolInput, error instanceof Error ? error : new Error(errorMsg));
7258
7217
  if (streamBuffer.hasCallback()) {
7259
7218
  streamBuffer.write(`\u274C **${externalTool.name} failed:**
@@ -7331,7 +7290,6 @@ var BaseLLM = class {
7331
7290
  return;
7332
7291
  }
7333
7292
  this.conversationSimilarityThreshold = threshold;
7334
- logger.info(`[${this.getProviderName()}] Conversation similarity threshold set to: ${threshold}`);
7335
7293
  }
7336
7294
  /**
7337
7295
  * Get the current conversation similarity threshold
@@ -7374,16 +7332,14 @@ var BaseLLM = class {
7374
7332
  * @param analysisContent - The text response containing component suggestions
7375
7333
  * @param components - List of available components
7376
7334
  * @param apiKey - Optional API key
7377
- * @param logCollector - Optional log collector
7378
7335
  * @param componentStreamCallback - Optional callback to stream primary KPI component as soon as it's identified
7379
7336
  * @returns Object containing matched components, layout title/description, and follow-up actions
7380
7337
  */
7381
- async matchComponentsFromAnalysis(analysisContent, components, userPrompt, apiKey, logCollector, componentStreamCallback, deferredTools, executedTools, collections, userId) {
7338
+ async matchComponentsFromAnalysis(analysisContent, components, userPrompt, apiKey, componentStreamCallback, deferredTools, executedTools, collections, userId) {
7382
7339
  const methodStartTime = Date.now();
7383
7340
  const methodName = "matchComponentsFromAnalysis";
7384
7341
  logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("complex")}`);
7385
7342
  try {
7386
- logger.debug(`[${this.getProviderName()}] Starting component matching from text response`);
7387
7343
  let availableComponentsText = "No components available";
7388
7344
  if (components && components.length > 0) {
7389
7345
  availableComponentsText = components.map((comp, idx) => {
@@ -7399,7 +7355,6 @@ var BaseLLM = class {
7399
7355
  }
7400
7356
  let deferredToolsText = "No deferred external tools for this request.";
7401
7357
  if (deferredTools && deferredTools.length > 0) {
7402
- logger.info(`[${this.getProviderName()}] Passing ${deferredTools.length} deferred tools to component matching`);
7403
7358
  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) => {
7404
7359
  return `${idx + 1}. **${tool.name}**
7405
7360
  toolId: "${tool.id}" (USE THIS EXACT VALUE - do not modify!)
@@ -7411,7 +7366,6 @@ var BaseLLM = class {
7411
7366
  }
7412
7367
  let executedToolsText = "No external tools were executed for data fetching.";
7413
7368
  if (executedTools && executedTools.length > 0) {
7414
- logger.info(`[${this.getProviderName()}] Passing ${executedTools.length} executed tools to component matching`);
7415
7369
  executedToolsText = "The following external tools were executed to fetch data.\n" + executedTools.map((tool, idx) => {
7416
7370
  let outputSchemaText = "Not available";
7417
7371
  let fieldNamesList = "";
@@ -7467,14 +7421,12 @@ ${fieldsText}`;
7467
7421
  KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext,
7468
7422
  CURRENT_DATETIME: getCurrentDateTimeForPrompt()
7469
7423
  });
7470
- logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
7471
7424
  logger.logLLMPrompt("matchComponentsFromAnalysis", "system", extractPromptText(prompts.system));
7472
7425
  logger.logLLMPrompt("matchComponentsFromAnalysis", "user", `Text Analysis:
7473
7426
  ${analysisContent}
7474
7427
 
7475
7428
  Executed Tools:
7476
7429
  ${executedToolsText}`);
7477
- logCollector?.info("Matching components from text response...");
7478
7430
  let fullResponseText = "";
7479
7431
  let answerComponentExtracted = false;
7480
7432
  const answerCallback = componentStreamCallback;
@@ -7534,18 +7486,7 @@ ${executedToolsText}`);
7534
7486
  ...answerComponentData.props
7535
7487
  }
7536
7488
  };
7537
- const streamTime = (/* @__PURE__ */ new Date()).toISOString();
7538
- logger.info(`[${this.getProviderName()}] \u2713 [${streamTime}] Answer component detected in stream: ${answerComponent.name} (${answerComponent.type})`);
7539
- logCollector?.info(`\u2713 Answer component: ${answerComponent.name} (${answerComponent.type}) - detected at ${streamTime}`);
7540
- if (answerComponentData.props?.query) {
7541
- logCollector?.logQuery(
7542
- "Answer component query",
7543
- answerComponentData.props.query,
7544
- { componentName: answerComponent.name, componentType: answerComponent.type, reasoning: answerComponentData.reasoning }
7545
- );
7546
- }
7547
7489
  let answerQuery = answerComponent.props?.query;
7548
- logger.info(`[${this.getProviderName()}] Answer component detected: ${answerComponent.name} (${answerComponent.type}), hasQuery: ${!!answerQuery}, hasDbExecute: ${!!collections?.["database"]?.["execute"]}`);
7549
7490
  if (answerQuery) {
7550
7491
  if (typeof answerQuery === "string") {
7551
7492
  answerQuery = ensureQueryLimit(answerQuery, this.defaultLimit, MAX_COMPONENT_QUERY_LIMIT);
@@ -7563,24 +7504,18 @@ ${executedToolsText}`);
7563
7504
  let currentQuery = answerQuery;
7564
7505
  let currentQueryStr = typeof answerQuery === "string" ? answerQuery : answerQuery?.sql || "";
7565
7506
  let lastError = "";
7566
- logger.info(`[${this.getProviderName()}] Validating answer component query before streaming...`);
7567
7507
  while (attempts < maxRetries && !validated) {
7568
7508
  attempts++;
7569
7509
  try {
7570
7510
  const cacheKey = this.queryService.getQueryCacheKey(currentQuery);
7571
7511
  if (cacheKey) {
7572
- logger.debug(`[${this.getProviderName()}] Answer component query validation attempt ${attempts}/${maxRetries}`);
7573
7512
  const result2 = await collections["database"]["execute"]({ sql: cacheKey });
7574
7513
  queryCache.set(cacheKey, result2);
7575
7514
  validated = true;
7576
7515
  if (currentQuery !== answerQuery) {
7577
7516
  answerComponent.props.query = currentQuery;
7578
7517
  }
7579
- logger.info(`[${this.getProviderName()}] \u2713 Answer component query validated (attempt ${attempts}) - STREAMING TO FRONTEND NOW`);
7580
- logCollector?.info(`\u2713 Answer component query validated - streaming to frontend`);
7581
- logger.info(`[${this.getProviderName()}] Calling answerCallback for: ${answerComponent.name}`);
7582
7518
  answerCallback(answerComponent);
7583
- logger.info(`[${this.getProviderName()}] answerCallback completed for: ${answerComponent.name}`);
7584
7519
  }
7585
7520
  } catch (validationError) {
7586
7521
  lastError = validationError instanceof Error ? validationError.message : String(validationError);
@@ -7616,7 +7551,6 @@ ${executedToolsText}`);
7616
7551
  }
7617
7552
  if (!validated) {
7618
7553
  logger.warn(`[${this.getProviderName()}] Answer component query validation failed after ${attempts} attempts - component will be excluded`);
7619
- logCollector?.warn(`Answer component query validation failed: ${lastError} - component will be excluded from response`);
7620
7554
  }
7621
7555
  })();
7622
7556
  } else {
@@ -7627,7 +7561,7 @@ ${executedToolsText}`);
7627
7561
  }
7628
7562
  }
7629
7563
  } catch (e) {
7630
- logger.debug(`[${this.getProviderName()}] Partial answerComponent parse failed, waiting for more data...`);
7564
+ logger.error(`[${this.getProviderName()}] Partial answerComponent parse failed, waiting for more data...`);
7631
7565
  }
7632
7566
  }
7633
7567
  }
@@ -7657,18 +7591,6 @@ ${executedToolsText}`);
7657
7591
  logger.file("\n=============================\nFull LLM response:", JSON.stringify(result, null, 2));
7658
7592
  const rawActions = result.actions || [];
7659
7593
  const actions = convertQuestionsToActions(rawActions);
7660
- if (matchedComponents.length > 0) {
7661
- matchedComponents.forEach((comp, idx) => {
7662
- logCollector?.info(` ${idx + 1}. ${comp.componentName} (${comp.componentType}): ${comp.reasoning}`);
7663
- if (comp.props?.query) {
7664
- logCollector?.logQuery(
7665
- `Component ${idx + 1} query`,
7666
- comp.props.query,
7667
- { componentName: comp.componentName, title: comp.props.title }
7668
- );
7669
- }
7670
- });
7671
- }
7672
7594
  const finalComponents = matchedComponents.map((mc) => {
7673
7595
  const originalComponent = components.find((c) => c.id === mc.componentId);
7674
7596
  if (!originalComponent) {
@@ -7693,27 +7615,22 @@ ${executedToolsText}`);
7693
7615
  }).filter(Boolean);
7694
7616
  let validatedComponents = finalComponents;
7695
7617
  if (collections?.["database"]?.["execute"]) {
7696
- logger.info(`[${this.getProviderName()}] Starting query validation for ${finalComponents.length} components...`);
7697
- logCollector?.info(`Validating queries for ${finalComponents.length} components...`);
7698
7618
  try {
7699
7619
  const validationResult = await this.queryService.validateComponentQueries(
7700
7620
  finalComponents,
7701
7621
  collections,
7702
- apiKey,
7703
- logCollector
7622
+ apiKey
7704
7623
  );
7705
7624
  validatedComponents = validationResult.components;
7706
7625
  const queriedComponents = finalComponents.filter((c) => c.props?.query);
7707
7626
  const validatedQueries = validatedComponents.filter((c) => c.props?.query);
7708
7627
  logger.info(`[${this.getProviderName()}] Query validation complete: ${validatedQueries.length}/${queriedComponents.length} queries validated`);
7709
- logCollector?.info(`Query validation complete: ${validatedQueries.length}/${queriedComponents.length} queries validated`);
7710
7628
  } catch (validationError) {
7711
7629
  const validationErrorMsg = validationError instanceof Error ? validationError.message : String(validationError);
7712
7630
  logger.error(`[${this.getProviderName()}] Query validation error: ${validationErrorMsg}`);
7713
- logCollector?.error(`Query validation error: ${validationErrorMsg}`);
7714
7631
  }
7715
7632
  } else {
7716
- logger.debug(`[${this.getProviderName()}] Skipping query validation - database execute function not available`);
7633
+ logger.error(`[${this.getProviderName()}] Skipping query validation - database execute function not available`);
7717
7634
  }
7718
7635
  const methodDuration = Date.now() - methodStartTime;
7719
7636
  logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | components: ${validatedComponents.length} | actions: ${actions.length}`);
@@ -7727,7 +7644,6 @@ ${executedToolsText}`);
7727
7644
  const methodDuration = Date.now() - methodStartTime;
7728
7645
  const errorMsg = error instanceof Error ? error.message : String(error);
7729
7646
  logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
7730
- logCollector?.error(`Failed to match components: ${errorMsg}`);
7731
7647
  return {
7732
7648
  components: [],
7733
7649
  layoutTitle: "Dashboard",
@@ -7740,7 +7656,7 @@ ${executedToolsText}`);
7740
7656
  * Classify user question into category and detect external tools needed
7741
7657
  * Determines if question is for data analysis, requires external tools, or needs text response
7742
7658
  */
7743
- async classifyQuestionCategory(userPrompt, apiKey, logCollector, conversationHistory, externalTools) {
7659
+ async classifyQuestionCategory(userPrompt, apiKey, conversationHistory, externalTools) {
7744
7660
  const methodStartTime = Date.now();
7745
7661
  const methodName = "classifyQuestionCategory";
7746
7662
  const promptPreview = userPrompt.substring(0, 50) + (userPrompt.length > 50 ? "..." : "");
@@ -7776,16 +7692,6 @@ ${executedToolsText}`);
7776
7692
  true
7777
7693
  // Parse as JSON
7778
7694
  );
7779
- logCollector?.logExplanation(
7780
- "Question category classified",
7781
- result.reasoning || "No reasoning provided",
7782
- {
7783
- category: result.category,
7784
- externalTools: result.externalTools || [],
7785
- dataAnalysisType: result.dataAnalysisType,
7786
- confidence: result.confidence
7787
- }
7788
- );
7789
7695
  const methodDuration = Date.now() - methodStartTime;
7790
7696
  logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | category: ${result.category} | confidence: ${result.confidence}% | tools: ${(result.externalTools || []).length}`);
7791
7697
  return {
@@ -7799,7 +7705,6 @@ ${executedToolsText}`);
7799
7705
  const methodDuration = Date.now() - methodStartTime;
7800
7706
  const errorMsg = error instanceof Error ? error.message : String(error);
7801
7707
  logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
7802
- logger.debug(`[${this.getProviderName()}] Category classification error details:`, error);
7803
7708
  throw error;
7804
7709
  }
7805
7710
  }
@@ -7808,7 +7713,7 @@ ${executedToolsText}`);
7808
7713
  * Takes a matched UI block from semantic search and modifies its props to answer the new question
7809
7714
  * Also adapts the cached text response to match the new question
7810
7715
  */
7811
- async adaptUIBlockParameters(currentUserPrompt, originalUserPrompt, matchedUIBlock, apiKey, logCollector, cachedTextResponse) {
7716
+ async adaptUIBlockParameters(currentUserPrompt, originalUserPrompt, matchedUIBlock, apiKey, cachedTextResponse) {
7812
7717
  const methodStartTime = Date.now();
7813
7718
  const methodName = "adaptUIBlockParameters";
7814
7719
  const promptPreview = currentUserPrompt.substring(0, 50) + (currentUserPrompt.length > 50 ? "..." : "");
@@ -7852,11 +7757,6 @@ ${executedToolsText}`);
7852
7757
  if (!result.success) {
7853
7758
  const methodDuration2 = Date.now() - methodStartTime;
7854
7759
  logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration2}ms | result: adaptation failed - ${result.reason}`);
7855
- logCollector?.warn(
7856
- "Could not adapt matched UI block",
7857
- "explanation",
7858
- { reason: result.reason }
7859
- );
7860
7760
  return {
7861
7761
  success: false,
7862
7762
  explanation: result.explanation || "Adaptation not possible"
@@ -7868,14 +7768,6 @@ ${executedToolsText}`);
7868
7768
  this.defaultLimit
7869
7769
  );
7870
7770
  }
7871
- logCollector?.logExplanation(
7872
- "UI block parameters adapted",
7873
- result.explanation || "Parameters adapted successfully",
7874
- {
7875
- parametersChanged: result.parametersChanged || [],
7876
- componentType: result.adaptedComponent?.type
7877
- }
7878
- );
7879
7771
  const methodDuration = Date.now() - methodStartTime;
7880
7772
  logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | result: success | changes: ${(result.parametersChanged || []).length}`);
7881
7773
  return {
@@ -7889,7 +7781,6 @@ ${executedToolsText}`);
7889
7781
  const methodDuration = Date.now() - methodStartTime;
7890
7782
  const errorMsg = error instanceof Error ? error.message : String(error);
7891
7783
  logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
7892
- logger.debug(`[${this.getProviderName()}] Adaptation error details:`, error);
7893
7784
  return {
7894
7785
  success: false,
7895
7786
  explanation: `Error adapting parameters: ${errorMsg}`
@@ -7902,14 +7793,12 @@ ${executedToolsText}`);
7902
7793
  * Supports tool calling for query execution with automatic retry on errors (max 3 attempts)
7903
7794
  * After generating text response, if components are provided, matches suggested components
7904
7795
  */
7905
- async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory, streamCallback, collections, components, externalTools, category, userId) {
7796
+ async generateTextResponse(userPrompt, apiKey, conversationHistory, streamCallback, collections, components, externalTools, category, userId) {
7906
7797
  const methodStartTime = Date.now();
7907
7798
  const methodName = "generateTextResponse";
7908
7799
  const promptPreview = userPrompt.substring(0, 50) + (userPrompt.length > 50 ? "..." : "");
7909
7800
  logger.info(`[${this.getProviderName()}] [TIMING] START ${methodName} | model: ${this.getModelForTask("complex")} | category: ${category} | prompt: "${promptPreview}"`);
7910
7801
  const errors = [];
7911
- logger.debug(`[${this.getProviderName()}] Starting text response generation`);
7912
- logger.debug(`[${this.getProviderName()}] User prompt: "${userPrompt.substring(0, 50)}..."`);
7913
7802
  try {
7914
7803
  let availableToolsDoc = "No external tools are available for this request.";
7915
7804
  if (externalTools && externalTools.length > 0) {
@@ -7973,9 +7862,6 @@ ${executedToolsText}`);
7973
7862
  });
7974
7863
  logger.logLLMPrompt("generateTextResponse", "system", extractPromptText(prompts.system));
7975
7864
  logger.logLLMPrompt("generateTextResponse", "user", extractPromptText(prompts.user));
7976
- logger.debug(`[${this.getProviderName()}] Loaded text-response prompts with schema`);
7977
- logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
7978
- logCollector?.info("Generating text response with query execution capability...");
7979
7865
  const tools = [{
7980
7866
  name: "execute_query",
7981
7867
  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.",
@@ -8004,7 +7890,6 @@ ${executedToolsText}`);
8004
7890
  const executableTools = externalTools.filter(
8005
7891
  (t) => t.executionType === "immediate" || t.executionType === "deferred" && t.userProvidedData
8006
7892
  );
8007
- logger.info(`[${this.getProviderName()}] Executable tools: ${executableTools.length} of ${externalTools.length} total`);
8008
7893
  const addedToolIds = /* @__PURE__ */ new Set();
8009
7894
  executableTools.forEach((tool) => {
8010
7895
  if (addedToolIds.has(tool.id)) {
@@ -8012,7 +7897,6 @@ ${executedToolsText}`);
8012
7897
  return;
8013
7898
  }
8014
7899
  addedToolIds.add(tool.id);
8015
- logger.info(`[${this.getProviderName()}] Processing executable tool:`, JSON.stringify(tool, null, 2));
8016
7900
  const properties = {};
8017
7901
  const required = [];
8018
7902
  Object.entries(tool.params || {}).forEach(([key, typeOrValue]) => {
@@ -8082,14 +7966,13 @@ ${executedToolsText}`);
8082
7966
  });
8083
7967
  });
8084
7968
  logger.info(`[${this.getProviderName()}] Added ${addedToolIds.size} unique tool definitions from ${executableTools.length} tool calls (${externalTools.length - executableTools.length} deferred tools await form input)`);
8085
- logger.info(`[${this.getProviderName()}] Complete tools array:`, JSON.stringify(tools, null, 2));
7969
+ logger.debug(`[${this.getProviderName()}] Complete tools array:`, JSON.stringify(tools, null, 2));
8086
7970
  }
8087
7971
  const streamBuffer = new StreamBuffer(streamCallback);
8088
7972
  const toolExecutor = new ToolExecutorService({
8089
7973
  providerName: this.getProviderName(),
8090
7974
  collections,
8091
- streamBuffer,
8092
- logCollector
7975
+ streamBuffer
8093
7976
  });
8094
7977
  const executableExternalTools = externalTools?.map((t) => ({
8095
7978
  id: t.id,
@@ -8118,12 +8001,10 @@ ${executedToolsText}`);
8118
8001
  },
8119
8002
  MAX_TOOL_CALLING_ITERATIONS
8120
8003
  );
8121
- logger.info(`[${this.getProviderName()}] Text response stream completed`);
8122
8004
  const textResponse = streamBuffer.getFullText() || result || "I apologize, but I was unable to generate a response.";
8123
8005
  if (toolExecutor.isMaxAttemptsReached()) {
8124
8006
  const methodDuration2 = Date.now() - methodStartTime;
8125
8007
  logger.warn(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration2}ms | result: max attempts reached`);
8126
- logCollector?.error("Failed to generate valid query after maximum attempts");
8127
8008
  return {
8128
8009
  success: false,
8129
8010
  errors: [`Maximum query attempts (${MAX_QUERY_ATTEMPTS}) reached. Unable to generate a valid query for your question.`],
@@ -8135,14 +8016,6 @@ ${executedToolsText}`);
8135
8016
  }
8136
8017
  };
8137
8018
  }
8138
- logCollector?.info(`Text response: ${textResponse.substring(0, 100)}${textResponse.length > 100 ? "..." : ""}`);
8139
- logCollector?.logExplanation(
8140
- "Text response generated",
8141
- "Generated plain text response with component suggestions",
8142
- {
8143
- textLength: textResponse.length
8144
- }
8145
- );
8146
8019
  streamBuffer.flush();
8147
8020
  if (streamBuffer.hasCallback() && components && components.length > 0 && category !== "general") {
8148
8021
  streamBuffer.write("\n\n\u{1F4CA} **Generating visualization components...**\n\n");
@@ -8154,8 +8027,6 @@ ${executedToolsText}`);
8154
8027
  let actions = [];
8155
8028
  if (category === "general") {
8156
8029
  logger.info(`[${this.getProviderName()}] Skipping component generation for general/conversational question`);
8157
- logCollector?.info("Skipping component generation for general question");
8158
- logger.info(`[${this.getProviderName()}] Generating actions for general question...`);
8159
8030
  const nextQuestions = await this.generateNextQuestions(
8160
8031
  userPrompt,
8161
8032
  null,
@@ -8163,23 +8034,16 @@ ${executedToolsText}`);
8163
8034
  void 0,
8164
8035
  // no component data
8165
8036
  apiKey,
8166
- logCollector,
8167
8037
  conversationHistory,
8168
8038
  textResponse
8169
8039
  // pass text response as context
8170
8040
  );
8171
8041
  actions = convertQuestionsToActions(nextQuestions);
8172
- logger.info(`[${this.getProviderName()}] Generated ${actions.length} follow-up actions for general question`);
8173
8042
  } else if (components && components.length > 0) {
8174
- logger.info(`[${this.getProviderName()}] Matching components from text response...`);
8175
- logger.info(`[${this.getProviderName()}] componentStreamCallback setup: hasCallback=${streamBuffer.hasCallback()}, category=${category}`);
8176
- const componentStreamCallback = streamBuffer.hasCallback() && category !== "data_modification" ? (component) => {
8177
- logger.info(`[${this.getProviderName()}] componentStreamCallback INVOKED for: ${component.name} (${component.type})`);
8043
+ const componentStreamCallback = streamBuffer.hasCallback() && category === "data_analysis" ? (component) => {
8178
8044
  const answerMarker = `__ANSWER_COMPONENT_START__${JSON.stringify(component)}__ANSWER_COMPONENT_END__`;
8179
8045
  streamBuffer.write(answerMarker);
8180
- logger.info(`[${this.getProviderName()}] Streamed answer component to frontend: ${component.name} (${component.type})`);
8181
8046
  } : void 0;
8182
- logger.info(`[${this.getProviderName()}] componentStreamCallback created: ${!!componentStreamCallback}`);
8183
8047
  const deferredTools = externalTools?.filter((t) => {
8184
8048
  if (t.executionType === "deferred" && !t.userProvidedData) return true;
8185
8049
  if (category === "data_modification" && !t.userProvidedData) {
@@ -8200,7 +8064,6 @@ ${executedToolsText}`);
8200
8064
  components,
8201
8065
  userPrompt,
8202
8066
  apiKey,
8203
- logCollector,
8204
8067
  componentStreamCallback,
8205
8068
  deferredTools,
8206
8069
  toolExecutor.getExecutedTools(),
@@ -8214,8 +8077,6 @@ ${executedToolsText}`);
8214
8077
  }
8215
8078
  let container_componet = null;
8216
8079
  if (matchedComponents.length > 0) {
8217
- logger.info(`[${this.getProviderName()}] Created MultiComponentContainer: "${layoutTitle}" with ${matchedComponents.length} components and ${actions.length} actions`);
8218
- logCollector?.info(`Created dashboard: "${layoutTitle}" with ${matchedComponents.length} components and ${actions.length} actions`);
8219
8080
  container_componet = {
8220
8081
  id: `container_${Date.now()}`,
8221
8082
  name: "MultiComponentContainer",
@@ -8247,7 +8108,6 @@ ${executedToolsText}`);
8247
8108
  const methodDuration = Date.now() - methodStartTime;
8248
8109
  const errorMsg = error instanceof Error ? error.message : String(error);
8249
8110
  logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
8250
- logCollector?.error(`Error generating text response: ${errorMsg}`);
8251
8111
  userPromptErrorLogger.logLlmError(
8252
8112
  this.getProviderName(),
8253
8113
  this.model,
@@ -8275,14 +8135,11 @@ ${executedToolsText}`);
8275
8135
  * 2. Category classification: Determine if data_analysis, requires_external_tools, or text_response
8276
8136
  * 3. Route appropriately based on category and response mode
8277
8137
  */
8278
- async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory, responseMode = "text", streamCallback, collections, externalTools, userId) {
8138
+ async handleUserRequest(userPrompt, components, apiKey, conversationHistory, responseMode = "text", streamCallback, collections, externalTools, userId) {
8279
8139
  const startTime = Date.now();
8280
- logger.info(`[${this.getProviderName()}] handleUserRequest called for user prompt: ${userPrompt}`);
8281
- logCollector?.info(`Starting request processing with mode: ${responseMode}`);
8282
8140
  logger.clearFile();
8283
8141
  logger.logLLMPrompt("handleUserRequest", "user", `User Prompt: ${userPrompt}`);
8284
8142
  try {
8285
- logger.info(`[${this.getProviderName()}] Step 1: Searching previous conversations...`);
8286
8143
  const conversationMatch = await conversation_search_default.searchConversationsWithReranking({
8287
8144
  userPrompt,
8288
8145
  collections,
@@ -8291,22 +8148,16 @@ ${executedToolsText}`);
8291
8148
  });
8292
8149
  if (conversationMatch) {
8293
8150
  logger.info(`[${this.getProviderName()}] \u2713 Found matching conversation with ${(conversationMatch.similarity * 100).toFixed(2)}% similarity`);
8294
- logCollector?.info(
8295
- `\u2713 Found similar conversation (${(conversationMatch.similarity * 100).toFixed(2)}% match)`
8296
- );
8297
8151
  const rawComponent = conversationMatch.uiBlock?.component || conversationMatch.uiBlock?.generatedComponentMetadata;
8298
8152
  const isValidComponent = rawComponent && typeof rawComponent === "object" && Object.keys(rawComponent).length > 0;
8299
8153
  const component = isValidComponent ? rawComponent : null;
8300
8154
  const cachedTextResponse = conversationMatch.uiBlock?.analysis || conversationMatch.uiBlock?.textResponse || conversationMatch.uiBlock?.text || "";
8301
8155
  if (this.containsFormComponent(component)) {
8302
8156
  logger.info(`[${this.getProviderName()}] Skipping cached result - Form components contain stale defaultValues, fetching fresh data`);
8303
- logCollector?.info("Skipping cache for form - fetching current values from database...");
8304
8157
  } else if (!component) {
8305
8158
  if (conversationMatch.similarity >= EXACT_MATCH_SIMILARITY_THRESHOLD) {
8306
8159
  const elapsedTime2 = Date.now() - startTime;
8307
- logger.info(`[${this.getProviderName()}] \u2713 Exact match for general question - returning cached text response`);
8308
- logCollector?.info(`\u2713 Exact match for general question - returning cached response`);
8309
- logCollector?.info(`Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
8160
+ logger.info(`[${this.getProviderName()}] \u2713 Exact match for general question - returning cached text response (${elapsedTime2}ms)`);
8310
8161
  return {
8311
8162
  success: true,
8312
8163
  data: {
@@ -8321,14 +8172,11 @@ ${executedToolsText}`);
8321
8172
  };
8322
8173
  } else {
8323
8174
  logger.info(`[${this.getProviderName()}] Similar match but no component (general question) - processing fresh`);
8324
- logCollector?.info("Similar match found but was a general conversation - processing as new question");
8325
8175
  }
8326
8176
  } else {
8327
8177
  if (conversationMatch.similarity >= EXACT_MATCH_SIMILARITY_THRESHOLD) {
8328
8178
  const elapsedTime2 = Date.now() - startTime;
8329
- logger.info(`[${this.getProviderName()}] \u2713 100% match - returning UI block directly without adaptation`);
8330
- logCollector?.info(`\u2713 Exact match (${(conversationMatch.similarity * 100).toFixed(2)}%) - returning cached result`);
8331
- logCollector?.info(`Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
8179
+ logger.info(`[${this.getProviderName()}] \u2713 100% match - returning UI block directly without adaptation (${elapsedTime2}ms)`);
8332
8180
  if (streamCallback && cachedTextResponse) {
8333
8181
  logger.info(`[${this.getProviderName()}] Streaming cached text response to frontend`);
8334
8182
  streamCallback(cachedTextResponse);
@@ -8347,22 +8195,18 @@ ${executedToolsText}`);
8347
8195
  errors: []
8348
8196
  };
8349
8197
  }
8350
- logCollector?.info(`Adapting parameters for similar question...`);
8198
+ logger.info(`[${this.getProviderName()}] Adapting parameters for similar question...`);
8351
8199
  const originalPrompt = conversationMatch.metadata?.userPrompt || "Previous question";
8352
8200
  const adaptResult = await this.adaptUIBlockParameters(
8353
8201
  userPrompt,
8354
8202
  originalPrompt,
8355
8203
  conversationMatch.uiBlock,
8356
8204
  apiKey,
8357
- logCollector,
8358
8205
  cachedTextResponse
8359
8206
  );
8360
8207
  if (adaptResult.success && adaptResult.adaptedComponent) {
8361
8208
  const elapsedTime2 = Date.now() - startTime;
8362
- logger.info(`[${this.getProviderName()}] \u2713 Successfully adapted UI block parameters`);
8363
- logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
8364
- logCollector?.info(`\u2713 UI block adapted successfully`);
8365
- logCollector?.info(`Total time taken: ${elapsedTime2}ms (${(elapsedTime2 / 1e3).toFixed(2)}s)`);
8209
+ logger.info(`[${this.getProviderName()}] \u2713 Successfully adapted UI block parameters (${elapsedTime2}ms)`);
8366
8210
  const textResponseToUse = adaptResult.adaptedTextResponse || cachedTextResponse;
8367
8211
  if (streamCallback && textResponseToUse) {
8368
8212
  logger.info(`[${this.getProviderName()}] Streaming ${adaptResult.adaptedTextResponse ? "adapted" : "cached"} text response to frontend`);
@@ -8383,65 +8227,57 @@ ${executedToolsText}`);
8383
8227
  errors: []
8384
8228
  };
8385
8229
  } else {
8386
- logger.info(`[${this.getProviderName()}] Could not adapt matched conversation, continuing to category classification`);
8387
- logCollector?.warn(`Could not adapt matched conversation: ${adaptResult.explanation}`);
8230
+ logger.info(`[${this.getProviderName()}] Could not adapt matched conversation: ${adaptResult.explanation}, continuing to category classification`);
8388
8231
  }
8389
8232
  }
8390
8233
  } else {
8391
8234
  logger.info(`[${this.getProviderName()}] No matching previous conversations found, proceeding to category classification`);
8392
- logCollector?.info("No similar previous conversations found. Proceeding to category classification...");
8393
8235
  }
8394
8236
  logger.info(`[${this.getProviderName()}] Step 2: Classifying question category...`);
8395
- logCollector?.info("Step 2: Classifying question category...");
8396
8237
  const categoryClassification = await this.classifyQuestionCategory(
8397
8238
  userPrompt,
8398
8239
  apiKey,
8399
- logCollector,
8400
8240
  conversationHistory,
8401
8241
  externalTools
8402
8242
  );
8403
8243
  logger.info(
8404
8244
  `[${this.getProviderName()}] Question classified as: ${categoryClassification.category} (confidence: ${categoryClassification.confidence}%)`
8405
8245
  );
8406
- logCollector?.info(
8407
- `Category: ${categoryClassification.category} | Confidence: ${categoryClassification.confidence}%`
8408
- );
8409
8246
  let toolsToUse = [];
8410
8247
  if (categoryClassification.externalTools && categoryClassification.externalTools.length > 0) {
8411
- logger.info(`[${this.getProviderName()}] Identified ${categoryClassification.externalTools.length} external tools needed`);
8412
- logCollector?.info(`Identified external tools: ${categoryClassification.externalTools.map((t) => t.name || t.type).join(", ")}`);
8413
- logger.info(`[${this.getProviderName()}] Raw external tools from classification: ${JSON.stringify(categoryClassification.externalTools, null, 2)}`);
8414
- toolsToUse = categoryClassification.externalTools?.map((t) => {
8248
+ logger.info(`[${this.getProviderName()}] Identified ${categoryClassification.externalTools.length} external tools needed: ${categoryClassification.externalTools.map((t) => t.name || t.type).join(", ")}`);
8249
+ logger.debug(`[${this.getProviderName()}] Raw external tools from classification: ${JSON.stringify(categoryClassification.externalTools, null, 2)}`);
8250
+ toolsToUse = categoryClassification.externalTools.reduce((acc, t) => {
8415
8251
  const realTool = externalTools?.find((tool) => tool.id === t.type);
8416
- logger.info(`[${this.getProviderName()}] Tool ${t.name}: executionType=${t.executionType}, userProvidedData=${t.userProvidedData ? "present" : "null"}`);
8417
- return {
8252
+ if (!realTool) {
8253
+ logger.warn(`[${this.getProviderName()}] Tool ${t.type} (${t.name}) not found in registered tools - skipping (likely hallucinated)`);
8254
+ return acc;
8255
+ }
8256
+ acc.push({
8418
8257
  id: t.type,
8419
8258
  name: t.name,
8420
8259
  description: t.description,
8421
8260
  params: t.parameters || {},
8422
- // NEW: Include execution type info from category classification
8261
+ // Include execution type info from category classification
8423
8262
  executionType: t.executionType || "immediate",
8424
8263
  executionReason: t.executionReason || "",
8425
8264
  requiredFields: t.requiredFields || [],
8426
8265
  userProvidedData: t.userProvidedData || null,
8427
- // CRITICAL: Include outputSchema from real tool for component config generation
8428
- outputSchema: realTool?.outputSchema,
8429
- fn: (() => {
8430
- if (realTool) {
8431
- logger.info(`[${this.getProviderName()}] Using real tool implementation for ${t.type}`);
8432
- return realTool.fn;
8433
- } else {
8434
- logger.warn(`[${this.getProviderName()}] Tool ${t.type} not found in registered tools`);
8435
- return async () => ({ success: false, message: `Tool ${t.name || t.type} not registered` });
8436
- }
8437
- })()
8438
- };
8439
- }) || [];
8266
+ // Include outputSchema from real tool for component config generation
8267
+ outputSchema: realTool.outputSchema,
8268
+ fn: realTool.fn
8269
+ });
8270
+ return acc;
8271
+ }, []);
8272
+ const validCount = toolsToUse.length;
8273
+ const hallucinatedCount = categoryClassification.externalTools.length - validCount;
8274
+ if (hallucinatedCount > 0) {
8275
+ logger.warn(`[${this.getProviderName()}] Filtered out ${hallucinatedCount} hallucinated/non-existent tools, ${validCount} valid tools remaining`);
8276
+ }
8440
8277
  }
8441
8278
  const textResponse = await this.generateTextResponse(
8442
8279
  userPrompt,
8443
8280
  apiKey,
8444
- logCollector,
8445
8281
  conversationHistory,
8446
8282
  streamCallback,
8447
8283
  collections,
@@ -8452,13 +8288,10 @@ ${executedToolsText}`);
8452
8288
  );
8453
8289
  const elapsedTime = Date.now() - startTime;
8454
8290
  logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
8455
- logCollector?.info(`Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
8456
8291
  return textResponse;
8457
8292
  } catch (error) {
8458
8293
  const errorMsg = error instanceof Error ? error.message : String(error);
8459
8294
  logger.error(`[${this.getProviderName()}] Error in handleUserRequest: ${errorMsg}`);
8460
- logger.debug(`[${this.getProviderName()}] Error details:`, error);
8461
- logCollector?.error(`Error processing request: ${errorMsg}`);
8462
8295
  userPromptErrorLogger.logError(
8463
8296
  "handleUserRequest",
8464
8297
  error instanceof Error ? error : new Error(errorMsg),
@@ -8466,7 +8299,6 @@ ${executedToolsText}`);
8466
8299
  );
8467
8300
  const elapsedTime = Date.now() - startTime;
8468
8301
  logger.info(`[${this.getProviderName()}] Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
8469
- logCollector?.info(`Total time taken: ${elapsedTime}ms (${(elapsedTime / 1e3).toFixed(2)}s)`);
8470
8302
  return {
8471
8303
  success: false,
8472
8304
  errors: [errorMsg],
@@ -8482,7 +8314,7 @@ ${executedToolsText}`);
8482
8314
  * This helps provide intelligent suggestions for follow-up queries
8483
8315
  * For general/conversational questions without components, pass textResponse instead
8484
8316
  */
8485
- async generateNextQuestions(originalUserPrompt, component, componentData, apiKey, logCollector, conversationHistory, textResponse) {
8317
+ async generateNextQuestions(originalUserPrompt, component, componentData, apiKey, conversationHistory, textResponse) {
8486
8318
  const methodStartTime = Date.now();
8487
8319
  const methodName = "generateNextQuestions";
8488
8320
  const promptPreview = originalUserPrompt.substring(0, 50) + (originalUserPrompt.length > 50 ? "..." : "");
@@ -8527,14 +8359,6 @@ ${executedToolsText}`);
8527
8359
  // Parse as JSON
8528
8360
  );
8529
8361
  const nextQuestions = result.nextQuestions || [];
8530
- logCollector?.logExplanation(
8531
- "Next questions generated",
8532
- "Generated intelligent follow-up questions based on component",
8533
- {
8534
- count: nextQuestions.length,
8535
- questions: nextQuestions
8536
- }
8537
- );
8538
8362
  const methodDuration = Date.now() - methodStartTime;
8539
8363
  logger.info(`[${this.getProviderName()}] [TIMING] DONE ${methodName} in ${methodDuration}ms | questions: ${nextQuestions.length}`);
8540
8364
  return nextQuestions;
@@ -8542,8 +8366,6 @@ ${executedToolsText}`);
8542
8366
  const methodDuration = Date.now() - methodStartTime;
8543
8367
  const errorMsg = error instanceof Error ? error.message : String(error);
8544
8368
  logger.error(`[${this.getProviderName()}] [TIMING] FAILED ${methodName} in ${methodDuration}ms | error: ${errorMsg}`);
8545
- logger.debug(`[${this.getProviderName()}] Next questions generation error details:`, error);
8546
- logCollector?.error(`Error generating next questions: ${errorMsg}`);
8547
8369
  return [];
8548
8370
  }
8549
8371
  }
@@ -8657,332 +8479,96 @@ function getLLMProviders() {
8657
8479
  return DEFAULT_PROVIDERS;
8658
8480
  }
8659
8481
  }
8660
- var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8661
- logger.debug("[useAnthropicMethod] Initializing Anthropic Claude matching method");
8662
- logger.debug(`[useAnthropicMethod] Response mode: ${responseMode}`);
8663
- const msg = `Using Anthropic Claude ${responseMode === "text" ? "text response" : "matching"} method...`;
8664
- logCollector?.info(msg);
8482
+ var useAnthropicMethod = async (prompt, components, apiKey, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8665
8483
  if (responseMode === "component" && components.length === 0) {
8666
8484
  const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
8667
8485
  logger.error("[useAnthropicMethod] No components available");
8668
- logCollector?.error(emptyMsg);
8669
8486
  return { success: false, errors: [emptyMsg] };
8670
8487
  }
8671
- logger.debug(`[useAnthropicMethod] Processing with ${components.length} components`);
8672
- const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8488
+ const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8673
8489
  logger.info(`[useAnthropicMethod] Successfully generated ${responseMode} using Anthropic`);
8674
8490
  return matchResult;
8675
8491
  };
8676
- var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8492
+ var useGroqMethod = async (prompt, components, apiKey, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8677
8493
  logger.debug("[useGroqMethod] Initializing Groq LLM matching method");
8678
8494
  logger.debug(`[useGroqMethod] Response mode: ${responseMode}`);
8679
- const msg = `Using Groq LLM ${responseMode === "text" ? "text response" : "matching"} method...`;
8680
- logger.info(msg);
8681
- logCollector?.info(msg);
8682
8495
  if (responseMode === "component" && components.length === 0) {
8683
8496
  const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
8684
8497
  logger.error("[useGroqMethod] No components available");
8685
- logCollector?.error(emptyMsg);
8686
8498
  return { success: false, errors: [emptyMsg] };
8687
8499
  }
8688
8500
  logger.debug(`[useGroqMethod] Processing with ${components.length} components`);
8689
- const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8501
+ const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8690
8502
  logger.info(`[useGroqMethod] Successfully generated ${responseMode} using Groq`);
8691
8503
  return matchResult;
8692
8504
  };
8693
- var useGeminiMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8505
+ var useGeminiMethod = async (prompt, components, apiKey, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8694
8506
  logger.debug("[useGeminiMethod] Initializing Gemini LLM matching method");
8695
8507
  logger.debug(`[useGeminiMethod] Response mode: ${responseMode}`);
8696
- const msg = `Using Gemini LLM ${responseMode === "text" ? "text response" : "matching"} method...`;
8697
- logger.info(msg);
8698
- logCollector?.info(msg);
8699
8508
  if (responseMode === "component" && components.length === 0) {
8700
8509
  const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
8701
8510
  logger.error("[useGeminiMethod] No components available");
8702
- logCollector?.error(emptyMsg);
8703
8511
  return { success: false, errors: [emptyMsg] };
8704
8512
  }
8705
8513
  logger.debug(`[useGeminiMethod] Processing with ${components.length} components`);
8706
- const matchResult = await geminiLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8514
+ const matchResult = await geminiLLM.handleUserRequest(prompt, components, apiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8707
8515
  logger.info(`[useGeminiMethod] Successfully generated ${responseMode} using Gemini`);
8708
8516
  return matchResult;
8709
8517
  };
8710
- var useOpenAIMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8518
+ var useOpenAIMethod = async (prompt, components, apiKey, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8711
8519
  logger.debug("[useOpenAIMethod] Initializing OpenAI GPT matching method");
8712
8520
  logger.debug(`[useOpenAIMethod] Response mode: ${responseMode}`);
8713
- const msg = `Using OpenAI GPT ${responseMode === "text" ? "text response" : "matching"} method...`;
8714
- logger.info(msg);
8715
- logCollector?.info(msg);
8716
8521
  if (responseMode === "component" && components.length === 0) {
8717
8522
  const emptyMsg = "Components not loaded in memory. Please ensure components are fetched first.";
8718
8523
  logger.error("[useOpenAIMethod] No components available");
8719
- logCollector?.error(emptyMsg);
8720
8524
  return { success: false, errors: [emptyMsg] };
8721
8525
  }
8722
8526
  logger.debug(`[useOpenAIMethod] Processing with ${components.length} components`);
8723
- const matchResult = await openaiLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8527
+ const matchResult = await openaiLLM.handleUserRequest(prompt, components, apiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8724
8528
  logger.info(`[useOpenAIMethod] Successfully generated ${responseMode} using OpenAI`);
8725
8529
  return matchResult;
8726
8530
  };
8727
- var getUserResponseFromCache = async (prompt) => {
8728
- return false;
8729
- };
8730
- var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8731
- logger.debug(`[get_user_response] Starting user response generation for prompt: "${prompt.substring(0, 50)}..."`);
8732
- logger.debug(`[get_user_response] Response mode: ${responseMode}`);
8733
- logger.debug("[get_user_response] Checking cache for existing response");
8734
- const userResponse = await getUserResponseFromCache(prompt);
8735
- if (userResponse) {
8736
- logger.info("[get_user_response] User response found in cache - returning cached result");
8737
- logCollector?.info("User response found in cache");
8738
- return {
8739
- success: true,
8740
- data: userResponse,
8741
- errors: []
8742
- };
8743
- }
8744
- logger.debug("[get_user_response] No cached response found, proceeding with LLM providers");
8531
+ var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, conversationHistory, responseMode = "component", streamCallback, collections, externalTools, userId) => {
8745
8532
  const providers = llmProviders || getLLMProviders();
8746
8533
  const errors = [];
8747
- const providerOrder = providers.join(", ");
8748
- logCollector?.info(`LLM Provider order: [${providerOrder}]`);
8749
- if (conversationHistory && conversationHistory.length > 0) {
8750
- const exchangeCount = conversationHistory.split("\n").filter((l) => l.startsWith("Q")).length;
8751
- logger.debug(`[get_user_response] Using conversation history with ${exchangeCount} previous exchanges`);
8752
- logCollector?.info(`Using conversation history with ${exchangeCount} previous exchanges`);
8753
- } else {
8754
- logger.debug("[get_user_response] No conversation history available");
8755
- }
8534
+ logger.info(`[get_user_response] LLM Provider order: [${providers.join(", ")}]`);
8756
8535
  for (let i = 0; i < providers.length; i++) {
8757
8536
  const provider = providers[i];
8758
8537
  const isLastProvider = i === providers.length - 1;
8759
- const attemptMsg = `Attempting provider: ${provider} (${i + 1}/${providers.length})`;
8760
- logCollector?.info(attemptMsg);
8538
+ logger.info(`[get_user_response] Attempting provider: ${provider} (${i + 1}/${providers.length})`);
8761
8539
  let result;
8762
8540
  if (provider === "anthropic") {
8763
- result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8541
+ result = await useAnthropicMethod(prompt, components, anthropicApiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8764
8542
  } else if (provider === "groq") {
8765
- result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8543
+ result = await useGroqMethod(prompt, components, groqApiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8766
8544
  } else if (provider === "gemini") {
8767
- result = await useGeminiMethod(prompt, components, geminiApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8545
+ result = await useGeminiMethod(prompt, components, geminiApiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8768
8546
  } else if (provider === "openai") {
8769
- result = await useOpenAIMethod(prompt, components, openaiApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8547
+ result = await useOpenAIMethod(prompt, components, openaiApiKey, conversationHistory, responseMode, streamCallback, collections, externalTools, userId);
8770
8548
  } else {
8771
8549
  logger.warn(`[get_user_response] Unknown provider: ${provider} - skipping`);
8772
8550
  errors.push(`Unknown provider: ${provider}`);
8773
8551
  continue;
8774
8552
  }
8775
8553
  if (result.success) {
8776
- const successMsg = `Success with provider: ${provider}`;
8777
- logger.info(`${successMsg}`);
8778
- logCollector?.info(successMsg);
8554
+ logger.info(`[get_user_response] Success with provider: ${provider}`);
8779
8555
  return result;
8780
8556
  } else {
8781
8557
  const providerErrors = result.errors.map((err) => `${provider}: ${err}`);
8782
8558
  errors.push(...providerErrors);
8783
- const warnMsg = `Provider ${provider} returned unsuccessful result: ${result.errors.join(", ")}`;
8784
- logger.warn(`[get_user_response] ${warnMsg}`);
8785
- logCollector?.warn(warnMsg);
8559
+ logger.warn(`[get_user_response] Provider ${provider} returned unsuccessful result: ${result.errors.join(", ")}`);
8786
8560
  if (!isLastProvider) {
8787
- const fallbackMsg = "Falling back to next provider...";
8788
- logger.info(`[get_user_response] ${fallbackMsg}`);
8789
- logCollector?.info(fallbackMsg);
8561
+ logger.info("[get_user_response] Falling back to next provider...");
8790
8562
  }
8791
8563
  }
8792
8564
  }
8793
- const failureMsg = `All LLM providers failed`;
8794
- logger.error(`[get_user_response] ${failureMsg}. Errors: ${errors.join("; ")}`);
8795
- logCollector?.error(`${failureMsg}. Errors: ${errors.join("; ")}`);
8565
+ logger.error(`[get_user_response] All LLM providers failed. Errors: ${errors.join("; ")}`);
8796
8566
  return {
8797
8567
  success: false,
8798
8568
  errors
8799
8569
  };
8800
8570
  };
8801
8571
 
8802
- // src/utils/log-collector.ts
8803
- var LOG_LEVEL_PRIORITY2 = {
8804
- errors: 0,
8805
- warnings: 1,
8806
- info: 2,
8807
- verbose: 3
8808
- };
8809
- var MESSAGE_LEVEL_PRIORITY2 = {
8810
- error: 0,
8811
- warn: 1,
8812
- info: 2,
8813
- debug: 3
8814
- };
8815
- var UILogCollector = class {
8816
- constructor(clientId, sendMessage, uiBlockId) {
8817
- this.logs = [];
8818
- this.uiBlockId = uiBlockId || null;
8819
- this.clientId = clientId;
8820
- this.sendMessage = sendMessage;
8821
- this.currentLogLevel = logger.getLogLevel();
8822
- }
8823
- /**
8824
- * Check if logging is enabled (uiBlockId is provided)
8825
- */
8826
- isEnabled() {
8827
- return this.uiBlockId !== null;
8828
- }
8829
- /**
8830
- * Check if a message should be logged based on current log level
8831
- */
8832
- shouldLog(messageLevel) {
8833
- const currentLevelPriority = LOG_LEVEL_PRIORITY2[this.currentLogLevel];
8834
- const messagePriority = MESSAGE_LEVEL_PRIORITY2[messageLevel];
8835
- return messagePriority <= currentLevelPriority;
8836
- }
8837
- /**
8838
- * Add a log entry with timestamp and immediately send to runtime
8839
- * Only logs that pass the log level filter are captured and sent
8840
- */
8841
- addLog(level, message, type, data) {
8842
- if (!this.shouldLog(level)) {
8843
- return;
8844
- }
8845
- const log = {
8846
- timestamp: Date.now(),
8847
- level,
8848
- message,
8849
- ...type && { type },
8850
- ...data && { data }
8851
- };
8852
- this.logs.push(log);
8853
- this.sendLogImmediately(log);
8854
- switch (level) {
8855
- case "error":
8856
- logger.error("UILogCollector:", log);
8857
- break;
8858
- case "warn":
8859
- logger.warn("UILogCollector:", log);
8860
- break;
8861
- case "info":
8862
- logger.info("UILogCollector:", log);
8863
- break;
8864
- case "debug":
8865
- logger.debug("UILogCollector:", log);
8866
- break;
8867
- }
8868
- }
8869
- /**
8870
- * Send a single log to runtime immediately
8871
- */
8872
- sendLogImmediately(log) {
8873
- if (!this.isEnabled()) {
8874
- return;
8875
- }
8876
- const response = {
8877
- id: this.uiBlockId,
8878
- type: "UI_LOGS",
8879
- from: { type: "data-agent" },
8880
- to: {
8881
- type: "runtime",
8882
- id: this.clientId
8883
- },
8884
- payload: {
8885
- logs: [log]
8886
- // Send single log in array
8887
- }
8888
- };
8889
- this.sendMessage(response);
8890
- }
8891
- /**
8892
- * Log info message
8893
- */
8894
- info(message, type, data) {
8895
- if (this.isEnabled()) {
8896
- this.addLog("info", message, type, data);
8897
- }
8898
- }
8899
- /**
8900
- * Log error message
8901
- */
8902
- error(message, type, data) {
8903
- if (this.isEnabled()) {
8904
- this.addLog("error", message, type, data);
8905
- }
8906
- }
8907
- /**
8908
- * Log warning message
8909
- */
8910
- warn(message, type, data) {
8911
- if (this.isEnabled()) {
8912
- this.addLog("warn", message, type, data);
8913
- }
8914
- }
8915
- /**
8916
- * Log debug message
8917
- */
8918
- debug(message, type, data) {
8919
- if (this.isEnabled()) {
8920
- this.addLog("debug", message, type, data);
8921
- }
8922
- }
8923
- /**
8924
- * Log LLM explanation with typed metadata
8925
- */
8926
- logExplanation(message, explanation, data) {
8927
- if (this.isEnabled()) {
8928
- this.addLog("info", message, "explanation", {
8929
- explanation,
8930
- ...data
8931
- });
8932
- }
8933
- }
8934
- /**
8935
- * Log generated query with typed metadata
8936
- */
8937
- logQuery(message, query, data) {
8938
- if (this.isEnabled()) {
8939
- this.addLog("info", message, "query", {
8940
- query,
8941
- ...data
8942
- });
8943
- }
8944
- }
8945
- /**
8946
- * Send all collected logs at once (optional, for final summary)
8947
- */
8948
- sendAllLogs() {
8949
- if (!this.isEnabled() || this.logs.length === 0) {
8950
- return;
8951
- }
8952
- const response = {
8953
- id: this.uiBlockId,
8954
- type: "UI_LOGS",
8955
- from: { type: "data-agent" },
8956
- to: {
8957
- type: "runtime",
8958
- id: this.clientId
8959
- },
8960
- payload: {
8961
- logs: this.logs
8962
- }
8963
- };
8964
- this.sendMessage(response);
8965
- }
8966
- /**
8967
- * Get all collected logs
8968
- */
8969
- getLogs() {
8970
- return [...this.logs];
8971
- }
8972
- /**
8973
- * Clear all logs
8974
- */
8975
- clearLogs() {
8976
- this.logs = [];
8977
- }
8978
- /**
8979
- * Set uiBlockId (in case it's provided later)
8980
- */
8981
- setUIBlockId(uiBlockId) {
8982
- this.uiBlockId = uiBlockId;
8983
- }
8984
- };
8985
-
8986
8572
  // src/utils/conversation-saver.ts
8987
8573
  function transformUIBlockForDB(uiblock, userPrompt, uiBlockId) {
8988
8574
  const component = uiblock?.generatedComponentMetadata && Object.keys(uiblock.generatedComponentMetadata).length > 0 ? uiblock.generatedComponentMetadata : null;
@@ -9113,7 +8699,6 @@ var CONTEXT_CONFIG = {
9113
8699
  // src/handlers/user-prompt-request.ts
9114
8700
  var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools) => {
9115
8701
  const errors = [];
9116
- logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
9117
8702
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
9118
8703
  if (!parseResult.success) {
9119
8704
  const zodError = parseResult.error;
@@ -9145,27 +8730,23 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
9145
8730
  if (!prompt) {
9146
8731
  errors.push("Prompt not found");
9147
8732
  }
9148
- logger.debug(`[REQUEST ${id}] Full request details - uiBlockId: ${existingUiBlockId}, threadId: ${threadId}, prompt: ${prompt}`);
9149
8733
  if (errors.length > 0) {
9150
8734
  return { success: false, errors, id, wsId };
9151
8735
  }
9152
- const logCollector = new UILogCollector(wsId, sendMessage, existingUiBlockId);
9153
8736
  const threadManager = ThreadManager.getInstance();
9154
8737
  let thread = threadManager.getThread(threadId);
9155
8738
  if (!thread) {
9156
8739
  thread = threadManager.createThread(threadId);
9157
8740
  logger.info(`Created new thread: ${threadId}`);
9158
8741
  }
9159
- logCollector.info(`Starting user prompt request with ${components.length} components`);
8742
+ logger.info(`Starting user prompt request with ${components.length} components`);
9160
8743
  const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
9161
8744
  const responseMode = payload.responseMode || "component";
9162
- logger.info("responseMode", responseMode);
9163
8745
  let streamCallback;
9164
8746
  let accumulatedStreamResponse = "";
9165
8747
  if (responseMode === "text") {
9166
8748
  streamCallback = (chunk) => {
9167
8749
  accumulatedStreamResponse += chunk;
9168
- logger.debug(`[STREAM] Sending chunk (${chunk.length} chars): "${chunk.substring(0, 20)}..."`);
9169
8750
  const streamMessage = {
9170
8751
  id: `stream_${existingUiBlockId}`,
9171
8752
  // Different ID pattern for streaming
@@ -9181,7 +8762,6 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
9181
8762
  }
9182
8763
  };
9183
8764
  sendMessage(streamMessage);
9184
- logger.debug(`[STREAM] Chunk sent to wsId: ${wsId}`);
9185
8765
  };
9186
8766
  }
9187
8767
  const userResponse = await get_user_response(
@@ -9192,7 +8772,6 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
9192
8772
  geminiApiKey,
9193
8773
  openaiApiKey,
9194
8774
  llmProviders,
9195
- logCollector,
9196
8775
  conversationHistory,
9197
8776
  responseMode,
9198
8777
  streamCallback,
@@ -9200,7 +8779,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
9200
8779
  externalTools,
9201
8780
  userId
9202
8781
  );
9203
- logCollector.info("User prompt request completed");
8782
+ logger.info("User prompt request completed");
9204
8783
  const uiBlockId = existingUiBlockId;
9205
8784
  if (!userResponse.success) {
9206
8785
  logger.error(`User prompt request failed with errors: ${userResponse.errors.join(", ")}`);
@@ -9267,9 +8846,6 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
9267
8846
  logger.info(
9268
8847
  `Skipping conversation save - response from exact semantic match (${(semanticSimilarity * 100).toFixed(2)}% similarity)`
9269
8848
  );
9270
- logCollector.info(
9271
- `Using exact cached result (${(semanticSimilarity * 100).toFixed(2)}% match) - not saving duplicate conversation`
9272
- );
9273
8849
  } else {
9274
8850
  const uiBlockData = uiBlock.toJSON();
9275
8851
  const saveResult = await saveConversation({
@@ -9477,7 +9053,7 @@ function sendResponse(id, res, sendMessage, clientId) {
9477
9053
  }
9478
9054
 
9479
9055
  // src/userResponse/next-questions.ts
9480
- async function generateNextQuestions(originalUserPrompt, component, componentData, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, logCollector, conversationHistory) {
9056
+ async function generateNextQuestions(originalUserPrompt, component, componentData, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, conversationHistory) {
9481
9057
  try {
9482
9058
  logger.debug("[generateNextQuestions] Starting next questions generation");
9483
9059
  logger.debug(`[generateNextQuestions] User prompt: "${originalUserPrompt?.substring(0, 50)}..."`);
@@ -9496,7 +9072,6 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
9496
9072
  const isLastProvider = i === providers.length - 1;
9497
9073
  try {
9498
9074
  logger.info(`[generateNextQuestions] Attempting provider: ${provider} (${i + 1}/${providers.length})`);
9499
- logCollector?.info(`Generating questions with ${provider}...`);
9500
9075
  let result = [];
9501
9076
  if (provider === "groq") {
9502
9077
  logger.debug("[generateNextQuestions] Using Groq LLM for next questions");
@@ -9505,7 +9080,6 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
9505
9080
  component,
9506
9081
  componentData,
9507
9082
  groqApiKey,
9508
- logCollector,
9509
9083
  conversationHistory
9510
9084
  );
9511
9085
  } else if (provider === "gemini") {
@@ -9515,7 +9089,6 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
9515
9089
  component,
9516
9090
  componentData,
9517
9091
  geminiApiKey,
9518
- logCollector,
9519
9092
  conversationHistory
9520
9093
  );
9521
9094
  } else if (provider === "openai") {
@@ -9525,7 +9098,6 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
9525
9098
  component,
9526
9099
  componentData,
9527
9100
  openaiApiKey,
9528
- logCollector,
9529
9101
  conversationHistory
9530
9102
  );
9531
9103
  } else {
@@ -9535,44 +9107,32 @@ async function generateNextQuestions(originalUserPrompt, component, componentDat
9535
9107
  component,
9536
9108
  componentData,
9537
9109
  anthropicApiKey,
9538
- logCollector,
9539
9110
  conversationHistory
9540
9111
  );
9541
9112
  }
9542
9113
  if (result && result.length > 0) {
9543
9114
  logger.info(`[generateNextQuestions] Successfully generated ${result.length} questions with ${provider}`);
9544
9115
  logger.debug(`[generateNextQuestions] Questions: ${JSON.stringify(result)}`);
9545
- logCollector?.info(`Generated ${result.length} follow-up questions`);
9546
9116
  return result;
9547
9117
  }
9548
- const warnMsg = `No questions generated from ${provider}${!isLastProvider ? ", trying next provider..." : ""}`;
9549
- logger.warn(`[generateNextQuestions] ${warnMsg}`);
9550
- if (!isLastProvider) {
9551
- logCollector?.warn(warnMsg);
9552
- }
9118
+ logger.warn(`[generateNextQuestions] No questions generated from ${provider}${!isLastProvider ? ", trying next provider..." : ""}`);
9553
9119
  } catch (providerError) {
9554
9120
  const errorMsg = providerError instanceof Error ? providerError.message : String(providerError);
9555
9121
  logger.error(`[generateNextQuestions] Provider ${provider} failed: ${errorMsg}`);
9556
9122
  logger.debug(`[generateNextQuestions] Provider error details:`, providerError);
9557
9123
  if (!isLastProvider) {
9558
- const fallbackMsg = `Provider ${provider} failed, trying next provider...`;
9559
- logger.info(`[generateNextQuestions] ${fallbackMsg}`);
9560
- logCollector?.warn(fallbackMsg);
9561
- } else {
9562
- logCollector?.error(`Failed to generate questions with ${provider}`);
9124
+ logger.info(`[generateNextQuestions] Provider ${provider} failed, trying next provider...`);
9563
9125
  }
9564
9126
  continue;
9565
9127
  }
9566
9128
  }
9567
9129
  logger.warn("[generateNextQuestions] All providers failed or returned no questions");
9568
- logCollector?.warn("Unable to generate follow-up questions");
9569
9130
  return [];
9570
9131
  } catch (error) {
9571
9132
  const errorMsg = error instanceof Error ? error.message : String(error);
9572
9133
  const errorStack = error instanceof Error ? error.stack : void 0;
9573
9134
  logger.error(`[generateNextQuestions] Error generating next questions: ${errorMsg}`);
9574
9135
  logger.debug("[generateNextQuestions] Error stack trace:", errorStack);
9575
- logCollector?.error(`Error generating next questions: ${errorMsg}`);
9576
9136
  return [];
9577
9137
  }
9578
9138
  }
@@ -9620,9 +9180,6 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
9620
9180
  return;
9621
9181
  }
9622
9182
  logger.info(`[ACTIONS_REQ ${id}] UIBlock retrieved successfully`);
9623
- logger.debug(`[ACTIONS_REQ ${id}] Creating UILogCollector for uiBlockId: ${uiBlockId}`);
9624
- const logCollector = new UILogCollector(wsId, sendMessage, uiBlockId);
9625
- logger.info(`[ACTIONS_REQ ${id}] UILogCollector initialized`);
9626
9183
  logger.debug(`[ACTIONS_REQ ${id}] Extracting data from UIBlock`);
9627
9184
  const userQuestion = uiBlock.getUserQuestion();
9628
9185
  const component = uiBlock.getComponentMetadata();
@@ -9636,13 +9193,11 @@ async function handleActionsRequest(data, sendMessage, anthropicApiKey, groqApiK
9636
9193
  logger.info(`[ACTIONS_REQ ${id}] Conversation history extracted: ${historyLineCount} lines`);
9637
9194
  logger.debug(`[ACTIONS_REQ ${id}] Conversation history preview:
9638
9195
  ${conversationHistory.substring(0, 200)}...`);
9639
- logCollector.info(`Generating actions for UIBlock: ${uiBlockId}`);
9640
- logger.info(`[ACTIONS_REQ ${id}] Generating actions for component: ${component?.name || "unknown"}`);
9196
+ logger.info(`[ACTIONS_REQ ${id}] Generating actions for UIBlock: ${uiBlockId}, component: ${component?.name || "unknown"}`);
9641
9197
  logger.debug(`[ACTIONS_REQ ${id}] Checking if actions are already cached`);
9642
9198
  const startTime = Date.now();
9643
9199
  const actions = await uiBlock.getOrFetchActions(async () => {
9644
9200
  logger.info(`[ACTIONS_REQ ${id}] Actions not cached, generating new actions...`);
9645
- logCollector.info("Generating follow-up questions...");
9646
9201
  logger.info(`[ACTIONS_REQ ${id}] Starting next questions generation with ${llmProviders?.join(", ") || "default"} providers`);
9647
9202
  const nextQuestions = await generateNextQuestions(
9648
9203
  userQuestion,
@@ -9653,7 +9208,6 @@ ${conversationHistory.substring(0, 200)}...`);
9653
9208
  geminiApiKey,
9654
9209
  openaiApiKey,
9655
9210
  llmProviders,
9656
- logCollector,
9657
9211
  conversationHistory
9658
9212
  );
9659
9213
  logger.info(`[ACTIONS_REQ ${id}] Generated ${nextQuestions.length} questions`);
@@ -9671,11 +9225,10 @@ ${conversationHistory.substring(0, 200)}...`);
9671
9225
  const processingTime = Date.now() - startTime;
9672
9226
  logger.info(`[ACTIONS_REQ ${id}] Actions retrieved in ${processingTime}ms - ${actions.length} actions total`);
9673
9227
  if (actions.length > 0) {
9674
- logCollector.info(`Generated ${actions.length} follow-up questions successfully`);
9228
+ logger.info(`[ACTIONS_REQ ${id}] Generated ${actions.length} follow-up questions successfully`);
9675
9229
  logger.debug(`[ACTIONS_REQ ${id}] Actions: ${actions.map((a) => a.name).join(", ")}`);
9676
9230
  } else {
9677
9231
  logger.warn(`[ACTIONS_REQ ${id}] No actions generated`);
9678
- logCollector.warn("No follow-up questions could be generated");
9679
9232
  }
9680
9233
  logger.debug(`[ACTIONS_REQ ${id}] Sending successful response to client`);
9681
9234
  sendResponse2(id, {
@@ -9694,15 +9247,6 @@ ${conversationHistory.substring(0, 200)}...`);
9694
9247
  const errorStack = error instanceof Error ? error.stack : void 0;
9695
9248
  logger.error(`[ACTIONS_REQ] Failed to handle actions request: ${errorMessage}`);
9696
9249
  logger.debug(`[ACTIONS_REQ] Error stack trace:`, errorStack);
9697
- try {
9698
- const parsedData = data;
9699
- if (parsedData?.id && parsedData?.from?.id) {
9700
- const logCollector = parsedData?.payload?.SA_RUNTIME?.uiBlockId ? new UILogCollector(parsedData.from.id, sendMessage, parsedData.payload.SA_RUNTIME.uiBlockId) : void 0;
9701
- logCollector?.error(`Failed to generate actions: ${errorMessage}`);
9702
- }
9703
- } catch (logError) {
9704
- logger.debug("[ACTIONS_REQ] Failed to send error logs to UI:", logError);
9705
- }
9706
9250
  sendResponse2(null, {
9707
9251
  success: false,
9708
9252
  error: errorMessage
@@ -10283,7 +9827,6 @@ function sendResponse3(id, res, sendMessage, clientId) {
10283
9827
  var dashboardManager = null;
10284
9828
  function setDashboardManager(manager) {
10285
9829
  dashboardManager = manager;
10286
- logger.info("DashboardManager instance set");
10287
9830
  }
10288
9831
  function getDashboardManager() {
10289
9832
  if (!dashboardManager) {
@@ -13610,6 +13153,190 @@ var ReportManager = class {
13610
13153
  }
13611
13154
  };
13612
13155
 
13156
+ // src/utils/log-collector.ts
13157
+ var LOG_LEVEL_PRIORITY2 = {
13158
+ errors: 0,
13159
+ warnings: 1,
13160
+ info: 2,
13161
+ verbose: 3
13162
+ };
13163
+ var MESSAGE_LEVEL_PRIORITY2 = {
13164
+ error: 0,
13165
+ warn: 1,
13166
+ info: 2,
13167
+ debug: 3
13168
+ };
13169
+ var UILogCollector = class {
13170
+ constructor(clientId, sendMessage, uiBlockId) {
13171
+ this.logs = [];
13172
+ this.uiBlockId = uiBlockId || null;
13173
+ this.clientId = clientId;
13174
+ this.sendMessage = sendMessage;
13175
+ this.currentLogLevel = logger.getLogLevel();
13176
+ }
13177
+ /**
13178
+ * Check if logging is enabled (uiBlockId is provided)
13179
+ */
13180
+ isEnabled() {
13181
+ return this.uiBlockId !== null;
13182
+ }
13183
+ /**
13184
+ * Check if a message should be logged based on current log level
13185
+ */
13186
+ shouldLog(messageLevel) {
13187
+ const currentLevelPriority = LOG_LEVEL_PRIORITY2[this.currentLogLevel];
13188
+ const messagePriority = MESSAGE_LEVEL_PRIORITY2[messageLevel];
13189
+ return messagePriority <= currentLevelPriority;
13190
+ }
13191
+ /**
13192
+ * Add a log entry with timestamp and immediately send to runtime
13193
+ * Only logs that pass the log level filter are captured and sent
13194
+ */
13195
+ addLog(level, message, type, data) {
13196
+ if (!this.shouldLog(level)) {
13197
+ return;
13198
+ }
13199
+ const log = {
13200
+ timestamp: Date.now(),
13201
+ level,
13202
+ message,
13203
+ ...type && { type },
13204
+ ...data && { data }
13205
+ };
13206
+ this.logs.push(log);
13207
+ this.sendLogImmediately(log);
13208
+ switch (level) {
13209
+ case "error":
13210
+ logger.error("UILogCollector:", log);
13211
+ break;
13212
+ case "warn":
13213
+ logger.warn("UILogCollector:", log);
13214
+ break;
13215
+ case "info":
13216
+ logger.info("UILogCollector:", log);
13217
+ break;
13218
+ case "debug":
13219
+ logger.debug("UILogCollector:", log);
13220
+ break;
13221
+ }
13222
+ }
13223
+ /**
13224
+ * Send a single log to runtime immediately
13225
+ */
13226
+ sendLogImmediately(log) {
13227
+ if (!this.isEnabled()) {
13228
+ return;
13229
+ }
13230
+ const response = {
13231
+ id: this.uiBlockId,
13232
+ type: "UI_LOGS",
13233
+ from: { type: "data-agent" },
13234
+ to: {
13235
+ type: "runtime",
13236
+ id: this.clientId
13237
+ },
13238
+ payload: {
13239
+ logs: [log]
13240
+ // Send single log in array
13241
+ }
13242
+ };
13243
+ this.sendMessage(response);
13244
+ }
13245
+ /**
13246
+ * Log info message
13247
+ */
13248
+ info(message, type, data) {
13249
+ if (this.isEnabled()) {
13250
+ this.addLog("info", message, type, data);
13251
+ }
13252
+ }
13253
+ /**
13254
+ * Log error message
13255
+ */
13256
+ error(message, type, data) {
13257
+ if (this.isEnabled()) {
13258
+ this.addLog("error", message, type, data);
13259
+ }
13260
+ }
13261
+ /**
13262
+ * Log warning message
13263
+ */
13264
+ warn(message, type, data) {
13265
+ if (this.isEnabled()) {
13266
+ this.addLog("warn", message, type, data);
13267
+ }
13268
+ }
13269
+ /**
13270
+ * Log debug message
13271
+ */
13272
+ debug(message, type, data) {
13273
+ if (this.isEnabled()) {
13274
+ this.addLog("debug", message, type, data);
13275
+ }
13276
+ }
13277
+ /**
13278
+ * Log LLM explanation with typed metadata
13279
+ */
13280
+ logExplanation(message, explanation, data) {
13281
+ if (this.isEnabled()) {
13282
+ this.addLog("info", message, "explanation", {
13283
+ explanation,
13284
+ ...data
13285
+ });
13286
+ }
13287
+ }
13288
+ /**
13289
+ * Log generated query with typed metadata
13290
+ */
13291
+ logQuery(message, query, data) {
13292
+ if (this.isEnabled()) {
13293
+ this.addLog("info", message, "query", {
13294
+ query,
13295
+ ...data
13296
+ });
13297
+ }
13298
+ }
13299
+ /**
13300
+ * Send all collected logs at once (optional, for final summary)
13301
+ */
13302
+ sendAllLogs() {
13303
+ if (!this.isEnabled() || this.logs.length === 0) {
13304
+ return;
13305
+ }
13306
+ const response = {
13307
+ id: this.uiBlockId,
13308
+ type: "UI_LOGS",
13309
+ from: { type: "data-agent" },
13310
+ to: {
13311
+ type: "runtime",
13312
+ id: this.clientId
13313
+ },
13314
+ payload: {
13315
+ logs: this.logs
13316
+ }
13317
+ };
13318
+ this.sendMessage(response);
13319
+ }
13320
+ /**
13321
+ * Get all collected logs
13322
+ */
13323
+ getLogs() {
13324
+ return [...this.logs];
13325
+ }
13326
+ /**
13327
+ * Clear all logs
13328
+ */
13329
+ clearLogs() {
13330
+ this.logs = [];
13331
+ }
13332
+ /**
13333
+ * Set uiBlockId (in case it's provided later)
13334
+ */
13335
+ setUIBlockId(uiBlockId) {
13336
+ this.uiBlockId = uiBlockId;
13337
+ }
13338
+ };
13339
+
13613
13340
  // src/services/cleanup-service.ts
13614
13341
  var CleanupService = class _CleanupService {
13615
13342
  constructor() {
@@ -13790,7 +13517,6 @@ var CleanupService = class _CleanupService {
13790
13517
  };
13791
13518
 
13792
13519
  // src/index.ts
13793
- var SDK_VERSION = "0.0.8";
13794
13520
  var DEFAULT_WS_URL = "wss://ws.superatom.ai/websocket";
13795
13521
  var SuperatomSDK = class {
13796
13522
  // 3.5 minutes (PING_INTERVAL + 30s grace)
@@ -13831,7 +13557,7 @@ var SuperatomSDK = class {
13831
13557
  if (config.queryCacheTTL !== void 0) {
13832
13558
  queryCache.setTTL(config.queryCacheTTL);
13833
13559
  }
13834
- 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`);
13560
+ 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`);
13835
13561
  this.userManager = new UserManager(this.projectId, 5e3);
13836
13562
  this.dashboardManager = new DashboardManager(this.projectId);
13837
13563
  this.reportManager = new ReportManager(this.projectId);
@@ -13885,7 +13611,6 @@ var SuperatomSDK = class {
13885
13611
  */
13886
13612
  initializeDashboardManager() {
13887
13613
  setDashboardManager(this.dashboardManager);
13888
- logger.info(`DashboardManager initialized for project: ${this.projectId}`);
13889
13614
  }
13890
13615
  /**
13891
13616
  * Get the DashboardManager instance for this SDK
@@ -13898,7 +13623,6 @@ var SuperatomSDK = class {
13898
13623
  */
13899
13624
  initializeReportManager() {
13900
13625
  setReportManager(this.reportManager);
13901
- logger.info(`ReportManager initialized for project: ${this.projectId}`);
13902
13626
  }
13903
13627
  /**
13904
13628
  * Get the ReportManager instance for this SDK
@@ -14276,7 +14000,6 @@ var SuperatomSDK = class {
14276
14000
  CONTEXT_CONFIG,
14277
14001
  CleanupService,
14278
14002
  LLM,
14279
- SDK_VERSION,
14280
14003
  STORAGE_CONFIG,
14281
14004
  SuperatomSDK,
14282
14005
  Thread,