@superatomai/sdk-node 0.0.50 → 0.0.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -10,12 +10,13 @@ var __export = (target, all) => {
10
10
 
11
11
  // src/utils/logger.ts
12
12
  import fs from "fs";
13
- var PREFIX, LOGSTREAM, LOG_LEVEL_PRIORITY, MESSAGE_LEVEL_PRIORITY, Logger, logger;
13
+ var PREFIX, LOG_FILE_PATH, LOGSTREAM, LOG_LEVEL_PRIORITY, MESSAGE_LEVEL_PRIORITY, Logger, logger;
14
14
  var init_logger = __esm({
15
15
  "src/utils/logger.ts"() {
16
16
  "use strict";
17
17
  PREFIX = "[SuperatomSDK]";
18
- LOGSTREAM = fs.createWriteStream("superatom-sdk.log", { flags: "a" });
18
+ LOG_FILE_PATH = "superatom-sdk.log";
19
+ LOGSTREAM = fs.createWriteStream(LOG_FILE_PATH, { flags: "a" });
19
20
  LOG_LEVEL_PRIORITY = {
20
21
  errors: 0,
21
22
  warnings: 1,
@@ -99,9 +100,43 @@ var init_logger = __esm({
99
100
  console.log(PREFIX, "[DEBUG]", ...args);
100
101
  }
101
102
  }
103
+ /**
104
+ * Write to log file
105
+ */
102
106
  file(...args) {
103
107
  LOGSTREAM.write(args.join(" ") + "\n");
104
108
  }
109
+ /**
110
+ * Clear the log file (call at start of new user request)
111
+ */
112
+ clearFile() {
113
+ LOGSTREAM.end();
114
+ LOGSTREAM = fs.createWriteStream(LOG_FILE_PATH, { flags: "w" });
115
+ LOGSTREAM.write(`
116
+ ${"=".repeat(80)}
117
+ `);
118
+ LOGSTREAM.write(`NEW REQUEST - ${(/* @__PURE__ */ new Date()).toISOString()}
119
+ `);
120
+ LOGSTREAM.write(`${"=".repeat(80)}
121
+
122
+ `);
123
+ }
124
+ /**
125
+ * Log LLM method prompts with clear labeling
126
+ */
127
+ logLLMPrompt(methodName, promptType, content) {
128
+ const header = `
129
+ ${"#".repeat(80)}
130
+ [LLM METHOD: ${methodName}] - ${promptType.toUpperCase()} PROMPT
131
+ ${"#".repeat(80)}
132
+ `;
133
+ LOGSTREAM.write(header);
134
+ LOGSTREAM.write(content);
135
+ LOGSTREAM.write(`
136
+ ${"#".repeat(80)}
137
+
138
+ `);
139
+ }
105
140
  };
106
141
  logger = new Logger();
107
142
  }
@@ -1019,8 +1054,20 @@ If adaptation is not possible or would fundamentally change the component:
1019
1054
 
1020
1055
  Analyze the user's request and:
1021
1056
  1. **Select the most appropriate component** from the available components list
1022
- 2. **Determine the data source**: Database query OR External tool (ERP)
1023
- 3. **Generate complete props** for the selected component including the data retrieval/modification method
1057
+ 2. **Determine the data source**: Database query OR External tool
1058
+ 3. **Generate complete props** for the selected component
1059
+
1060
+ ## Available External Tools
1061
+
1062
+ The following external tools are available:
1063
+
1064
+ {{AVAILABLE_TOOLS}}
1065
+
1066
+ When a tool is needed to complete the user's request:
1067
+ 1. **Analyze the request** to determine which tool is needed
1068
+ 2. **Extract parameters** from the user's question
1069
+ 3. **Execute the tool** by calling it with the extracted parameters
1070
+ 4. **Use the results** to configure the component (field names for axes, columns, etc.)
1024
1071
 
1025
1072
  ## Component Selection Rules
1026
1073
 
@@ -1176,7 +1223,20 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1176
1223
 
1177
1224
  1. **Create a filter component** based on the user's request
1178
1225
  2. **Update existing components** with dynamic title/description interpolation if needed
1179
- 3. **Preserve all existing props** - the filter system handles param merging at runtime
1226
+ 3. **Set default values in component externalTool.params** that match the filter's default option
1227
+ 4. **Preserve all existing props** - the filter system handles param merging at runtime
1228
+
1229
+ ## Available External Tools
1230
+
1231
+ The following external tools are available:
1232
+
1233
+ {{AVAILABLE_TOOLS}}
1234
+
1235
+ When a tool is needed to complete the user's request:
1236
+ 1. **Analyze the request** to determine which tool is needed
1237
+ 2. **Extract parameters** from the user's question
1238
+ 3. **Execute the tool** by calling it with the extracted parameters
1239
+ 4. **Use the results** to configure the filter and components properly
1180
1240
 
1181
1241
  ## How The Filter System Works
1182
1242
 
@@ -1206,16 +1266,20 @@ Use \`{%filterKeyLabel%}\` syntax for dynamic text:
1206
1266
  ## Updating Existing Components
1207
1267
 
1208
1268
  **IMPORTANT - Parameter Handling:**
1209
- - Do NOT change existing parameter values to placeholders
1210
- - Keep all existing/default parameter values as they are
1211
1269
  - The filter system MERGES params at runtime: filter params override component defaults
1270
+ - Component's \`externalTool.params\` should have DEFAULT values matching the filter's default option
1271
+ - This ensures the component shows correct data on initial load before user changes the filter
1212
1272
 
1213
1273
  **What to modify in existing components:**
1214
1274
  - Modify \`title\` for \`{%filterKeyLabel%}\` interpolation (only if title exists)
1215
1275
  - Modify \`description\` for interpolation (only if description exists)
1216
- - Modify other props only if specifically needed for the filter to function
1276
+ - Set \`externalTool.params\` default values to match filter's default option params
1217
1277
  - Copy ALL other props exactly as provided
1218
1278
 
1279
+ **Example - Setting default params:**
1280
+ If filter has default option with params: \`{ startDate: "2025-01-01", endDate: "2025-01-31" }\`
1281
+ Then component's externalTool should have: \`{ params: { startDate: "2025-01-01", endDate: "2025-01-31" } }\`
1282
+
1219
1283
  ### Database Query Rules
1220
1284
  {{DATABASE_RULES}}
1221
1285
 
@@ -1263,10 +1327,11 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1263
1327
  **CRITICAL RULES:**
1264
1328
  1. Return ONLY valid JSON (no markdown code blocks)
1265
1329
  2. **COPY ALL existing props** - modify title/description for interpolation only if they exist
1266
- 3. **DO NOT change parameter values** - keep existing defaults, filter merges at runtime
1330
+ 3. **Set externalTool.params defaults** to match the filter's default option params
1267
1331
  4. Use \`{%filterKeyLabel%}\` for dynamic text (NOT \`{{...}}\` or \`$...\`)
1268
1332
  5. Filter \`params\` must have ACTUAL values (real dates, strings), not placeholders
1269
1333
  6. Each filter option needs: label, value, params (and optionally isDefault)
1334
+ 7. Component default params MUST match filter default - this ensures correct initial data load
1270
1335
 
1271
1336
  ## Database Schema
1272
1337
  {{SCHEMA_DOC}}
@@ -2309,6 +2374,57 @@ var KbNodesRequestMessageSchema = z3.object({
2309
2374
  type: z3.literal("KB_NODES"),
2310
2375
  payload: KbNodesRequestPayloadSchema
2311
2376
  });
2377
+ var MenusQueryFiltersSchema = z3.object({
2378
+ parentId: z3.number().nullable().optional(),
2379
+ isActive: z3.boolean().optional()
2380
+ });
2381
+ var MenusRequestPayloadSchema = z3.object({
2382
+ operation: z3.enum([
2383
+ "create",
2384
+ "update",
2385
+ "delete",
2386
+ "getAll",
2387
+ "getOne",
2388
+ "getRootMenus",
2389
+ "getChildMenus",
2390
+ "getHierarchy",
2391
+ "query",
2392
+ "reorder"
2393
+ ]),
2394
+ data: z3.object({
2395
+ id: z3.number().optional(),
2396
+ name: z3.string().optional(),
2397
+ componentName: z3.string().optional(),
2398
+ icon: z3.string().optional(),
2399
+ userMessage: z3.string().optional(),
2400
+ parentId: z3.number().nullable().optional(),
2401
+ sortOrder: z3.number().optional(),
2402
+ props: z3.record(z3.unknown()).optional(),
2403
+ isActive: z3.boolean().optional(),
2404
+ // Query operation fields
2405
+ filters: MenusQueryFiltersSchema.optional(),
2406
+ limit: z3.number().optional(),
2407
+ sort: z3.enum(["ASC", "DESC"]).optional(),
2408
+ // Reorder operation fields
2409
+ items: z3.array(z3.object({
2410
+ id: z3.number(),
2411
+ sortOrder: z3.number()
2412
+ })).optional()
2413
+ }).optional()
2414
+ });
2415
+ var MenusRequestMessageSchema = z3.object({
2416
+ id: z3.string(),
2417
+ from: MessageParticipantSchema,
2418
+ type: z3.literal("MENUS"),
2419
+ payload: MenusRequestPayloadSchema
2420
+ });
2421
+ var MenusResponsePayloadSchema = z3.object({
2422
+ success: z3.boolean(),
2423
+ error: z3.string().optional(),
2424
+ data: z3.any().optional(),
2425
+ count: z3.number().optional(),
2426
+ message: z3.string().optional()
2427
+ });
2312
2428
  var DashCompRequestPayloadSchema = z3.object({
2313
2429
  prompt: z3.string(),
2314
2430
  userId: z3.string().optional(),
@@ -5669,30 +5785,35 @@ ${JSON.stringify(tool.requiredFields || [], null, 2)}`;
5669
5785
  let executedToolsText = "No external tools were executed for data fetching.";
5670
5786
  if (executedTools && executedTools.length > 0) {
5671
5787
  logger.info(`[${this.getProviderName()}] Passing ${executedTools.length} executed tools to component matching`);
5672
- executedToolsText = "The following external tools were executed to fetch data.\n**IMPORTANT: For components displaying this data, use externalTool prop instead of query.**\n**IMPORTANT: Use the outputSchema fields to set correct config keys (xAxisKey, yAxisKey, valueKey, nameKey, etc.)**\n**IMPORTANT: Use the result data to populate deferred tool parameters when applicable.**\n\n" + executedTools.map((tool, idx) => {
5788
+ executedToolsText = "The following external tools were executed to fetch data.\n**IMPORTANT: For components displaying this data, use externalTool prop instead of query.**\n**IMPORTANT: Use ONLY the field names listed in outputSchema for config keys.**\n\n" + executedTools.map((tool, idx) => {
5673
5789
  let outputSchemaText = "Not available";
5790
+ let fieldNamesList = "";
5674
5791
  let recordCount = "unknown";
5675
5792
  if (tool.outputSchema) {
5676
5793
  const fields = tool.outputSchema.fields || [];
5677
5794
  recordCount = tool.result?._recordCount || (Array.isArray(tool.result) ? tool.result.length : "unknown");
5795
+ const numericFields = fields.filter((f) => f.type === "number").map((f) => f.name);
5796
+ const stringFields = fields.filter((f) => f.type === "string").map((f) => f.name);
5797
+ fieldNamesList = `
5798
+ \u{1F4CA} NUMERIC FIELDS (use for yAxisKey, valueKey, aggregationField): ${numericFields.join(", ") || "none"}
5799
+ \u{1F4DD} STRING FIELDS (use for xAxisKey, groupBy, nameKey): ${stringFields.join(", ") || "none"}`;
5800
+ const fieldsText = fields.map(
5801
+ (f) => ` "${f.name}" (${f.type}): ${f.description}`
5802
+ ).join("\n");
5678
5803
  outputSchemaText = `${tool.outputSchema.description}
5679
- Fields in EACH ROW (per-row values, NOT aggregates):
5680
- ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")}`;
5804
+ Fields:
5805
+ ${fieldsText}`;
5681
5806
  }
5682
5807
  return `${idx + 1}. **${tool.name}**
5683
- toolId: "${tool.id}" (USE THIS EXACT VALUE for externalTool.toolId)
5684
- toolName: "${tool.name}" (USE THIS EXACT VALUE for externalTool.toolName)
5685
- parameters: ${JSON.stringify(tool.params || {})} (USE THESE for externalTool.parameters)
5808
+ toolId: "${tool.id}"
5809
+ toolName: "${tool.name}"
5810
+ parameters: ${JSON.stringify(tool.params || {})}
5686
5811
  recordCount: ${recordCount} rows returned
5687
- outputSchema: ${outputSchemaText}
5688
- \u26A0\uFE0F DO NOT embed this tool's data in SQL - use externalTool prop OR query database tables`;
5812
+ outputSchema: ${outputSchemaText}${fieldNamesList}`;
5689
5813
  }).join("\n\n");
5690
5814
  }
5691
5815
  const schemaDoc = schema.generateSchemaDocumentation();
5692
5816
  const databaseRules = await promptLoader.loadDatabaseRules();
5693
- logger.file("\n=============================\nText analysis response:", analysisContent);
5694
- logger.file("\n=============================\nDeferred tools:", deferredToolsText);
5695
- logger.file("\n=============================\nExecuted tools:", executedToolsText);
5696
5817
  const prompts = await promptLoader.loadPrompts("match-text-components", {
5697
5818
  ANALYSIS_CONTENT: analysisContent,
5698
5819
  AVAILABLE_COMPONENTS: availableComponentsText,
@@ -5702,7 +5823,13 @@ ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")
5702
5823
  EXECUTED_TOOLS: executedToolsText
5703
5824
  });
5704
5825
  logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
5705
- logger.file("\n=============================\nmatch text components system prompt:", prompts.system);
5826
+ const systemPromptStr = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
5827
+ logger.logLLMPrompt("matchComponentsFromAnalysis", "system", systemPromptStr);
5828
+ logger.logLLMPrompt("matchComponentsFromAnalysis", "user", `Text Analysis:
5829
+ ${analysisContent}
5830
+
5831
+ Executed Tools:
5832
+ ${executedToolsText}`);
5706
5833
  logCollector?.info("Matching components from text response...");
5707
5834
  let fullResponseText = "";
5708
5835
  let answerComponentExtracted = false;
@@ -5834,6 +5961,85 @@ ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")
5834
5961
  if (!isValidTool) {
5835
5962
  logger.warn(`[${this.getProviderName()}] externalTool.toolId "${toolId}" not found in executed tools [${validToolIds.join(", ")}], setting to null`);
5836
5963
  cleanedProps.externalTool = null;
5964
+ } else {
5965
+ const executedTool = executedTools?.find((t) => t.id === toolId);
5966
+ if (executedTool?.outputSchema?.fields && cleanedProps.config) {
5967
+ const validFieldNames = executedTool.outputSchema.fields.map((f) => f.name);
5968
+ const validFieldNamesLower = validFieldNames.map((n) => n.toLowerCase());
5969
+ const findMatchingField = (fieldName, configKey) => {
5970
+ if (!fieldName) return null;
5971
+ const lowerField = fieldName.toLowerCase();
5972
+ const exactIdx = validFieldNamesLower.indexOf(lowerField);
5973
+ if (exactIdx !== -1) return validFieldNames[exactIdx];
5974
+ const containsMatches = validFieldNames.filter(
5975
+ (_, i) => validFieldNamesLower[i].includes(lowerField) || lowerField.includes(validFieldNamesLower[i])
5976
+ );
5977
+ if (containsMatches.length === 1) return containsMatches[0];
5978
+ const fieldTypes = executedTool.outputSchema.fields.reduce((acc, f) => {
5979
+ acc[f.name] = f.type;
5980
+ return acc;
5981
+ }, {});
5982
+ const numericConfigKeys = ["yAxisKey", "valueKey", "aggregationField", "sizeKey"];
5983
+ const stringConfigKeys = ["xAxisKey", "nameKey", "labelKey", "groupBy"];
5984
+ if (numericConfigKeys.includes(configKey)) {
5985
+ const numericFields = validFieldNames.filter((f) => fieldTypes[f] === "number");
5986
+ const match = numericFields.find((f) => f.toLowerCase().includes(lowerField) || lowerField.includes(f.toLowerCase()));
5987
+ if (match) return match;
5988
+ if (numericFields.length > 0) {
5989
+ logger.warn(`[${this.getProviderName()}] No match for "${fieldName}", using first numeric field: ${numericFields[0]}`);
5990
+ return numericFields[0];
5991
+ }
5992
+ }
5993
+ if (stringConfigKeys.includes(configKey)) {
5994
+ const stringFields = validFieldNames.filter((f) => fieldTypes[f] === "string");
5995
+ const match = stringFields.find((f) => f.toLowerCase().includes(lowerField) || lowerField.includes(f.toLowerCase()));
5996
+ if (match) return match;
5997
+ if (stringFields.length > 0) {
5998
+ logger.warn(`[${this.getProviderName()}] No match for "${fieldName}", using first string field: ${stringFields[0]}`);
5999
+ return stringFields[0];
6000
+ }
6001
+ }
6002
+ logger.warn(`[${this.getProviderName()}] No match for "${fieldName}", using first field: ${validFieldNames[0]}`);
6003
+ return validFieldNames[0];
6004
+ };
6005
+ const configFieldsToValidate = [
6006
+ "xAxisKey",
6007
+ "yAxisKey",
6008
+ "valueKey",
6009
+ "nameKey",
6010
+ "labelKey",
6011
+ "groupBy",
6012
+ "aggregationField",
6013
+ "seriesKey",
6014
+ "sizeKey",
6015
+ "xAggregationField",
6016
+ "yAggregationField"
6017
+ ];
6018
+ for (const configKey of configFieldsToValidate) {
6019
+ const fieldValue = cleanedProps.config[configKey];
6020
+ if (fieldValue && typeof fieldValue === "string") {
6021
+ if (!validFieldNames.includes(fieldValue)) {
6022
+ const correctedField = findMatchingField(fieldValue, configKey);
6023
+ if (correctedField) {
6024
+ logger.warn(`[${this.getProviderName()}] Correcting config.${configKey}: "${fieldValue}" \u2192 "${correctedField}"`);
6025
+ cleanedProps.config[configKey] = correctedField;
6026
+ }
6027
+ }
6028
+ }
6029
+ }
6030
+ if (Array.isArray(cleanedProps.config.series)) {
6031
+ cleanedProps.config.series = cleanedProps.config.series.map((s) => {
6032
+ if (s.dataKey && typeof s.dataKey === "string" && !validFieldNames.includes(s.dataKey)) {
6033
+ const correctedField = findMatchingField(s.dataKey, "yAxisKey");
6034
+ if (correctedField) {
6035
+ logger.warn(`[${this.getProviderName()}] Correcting series.dataKey: "${s.dataKey}" \u2192 "${correctedField}"`);
6036
+ return { ...s, dataKey: correctedField };
6037
+ }
6038
+ }
6039
+ return s;
6040
+ });
6041
+ }
6042
+ }
5837
6043
  }
5838
6044
  }
5839
6045
  if (cleanedProps.query) {
@@ -5891,6 +6097,10 @@ ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")
5891
6097
  AVAILABLE_TOOLS: availableToolsDoc,
5892
6098
  SCHEMA_DOC: schemaDoc || "No database schema available"
5893
6099
  });
6100
+ const systemPrompt = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
6101
+ const userPromptText = Array.isArray(prompts.user) ? prompts.user.join("\n") : prompts.user;
6102
+ logger.logLLMPrompt("classifyQuestionCategory", "system", systemPrompt);
6103
+ logger.logLLMPrompt("classifyQuestionCategory", "user", userPromptText);
5894
6104
  const result = await LLM.stream(
5895
6105
  {
5896
6106
  sys: prompts.system,
@@ -6078,7 +6288,6 @@ ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")
6078
6288
  collections,
6079
6289
  topK: 1
6080
6290
  });
6081
- logger.file("\n=============================\nknowledge base context:", knowledgeBaseContext);
6082
6291
  const prompts = await promptLoader.loadPrompts("text-response", {
6083
6292
  USER_PROMPT: userPrompt,
6084
6293
  CONVERSATION_HISTORY: conversationHistory || "No previous conversation",
@@ -6087,8 +6296,10 @@ ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")
6087
6296
  KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext || "No additional knowledge base context available.",
6088
6297
  AVAILABLE_EXTERNAL_TOOLS: availableToolsDoc
6089
6298
  });
6090
- logger.file("\n=============================\nsystem prompt:", prompts.system);
6091
- logger.file("\n=============================\nuser prompt:", prompts.user);
6299
+ const sysPrompt = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
6300
+ const usrPrompt = Array.isArray(prompts.user) ? prompts.user.join("\n") : prompts.user;
6301
+ logger.logLLMPrompt("generateTextResponse", "system", sysPrompt);
6302
+ logger.logLLMPrompt("generateTextResponse", "user", usrPrompt);
6092
6303
  logger.debug(`[${this.getProviderName()}] Loaded text-response prompts with schema`);
6093
6304
  logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
6094
6305
  logCollector?.info("Generating text response with query execution capability...");
@@ -6474,7 +6685,6 @@ ${errorMsg}
6474
6685
  data: {
6475
6686
  text: textResponse,
6476
6687
  // Include the streamed text showing all attempts
6477
- matchedComponents: [],
6478
6688
  actions: [],
6479
6689
  method: `${this.getProviderName()}-text-response-max-attempts`
6480
6690
  }
@@ -6572,7 +6782,6 @@ ${errorMsg}
6572
6782
  success: true,
6573
6783
  data: {
6574
6784
  text: textResponse,
6575
- matchedComponents,
6576
6785
  component: container_componet,
6577
6786
  actions,
6578
6787
  method: `${this.getProviderName()}-text-response`
@@ -6596,7 +6805,6 @@ ${errorMsg}
6596
6805
  errors,
6597
6806
  data: {
6598
6807
  text: "I apologize, but I encountered an error while processing your question. Please try rephrasing or ask something else.",
6599
- matchedComponents: [],
6600
6808
  actions: [],
6601
6809
  method: `${this.getProviderName()}-text-response-error`
6602
6810
  }
@@ -6620,6 +6828,8 @@ ${errorMsg}
6620
6828
  const startTime = Date.now();
6621
6829
  logger.info(`[${this.getProviderName()}] handleUserRequest called for user prompt: ${userPrompt}`);
6622
6830
  logCollector?.info(`Starting request processing with mode: ${responseMode}`);
6831
+ logger.clearFile();
6832
+ logger.logLLMPrompt("handleUserRequest", "user", `User Prompt: ${userPrompt}`);
6623
6833
  try {
6624
6834
  logger.info(`[${this.getProviderName()}] Step 1: Searching previous conversations...`);
6625
6835
  logCollector?.info("Step 1: Searching for similar previous conversations...");
@@ -6627,8 +6837,8 @@ ${errorMsg}
6627
6837
  userPrompt,
6628
6838
  collections,
6629
6839
  userId,
6630
- similarityThreshold: 0.75
6631
- // 75% threshold
6840
+ similarityThreshold: 0.8
6841
+ // 80% threshold
6632
6842
  });
6633
6843
  if (conversationMatch) {
6634
6844
  logger.info(`[${this.getProviderName()}] \u2713 Found matching conversation with ${(conversationMatch.similarity * 100).toFixed(2)}% similarity`);
@@ -6653,7 +6863,6 @@ ${errorMsg}
6653
6863
  data: {
6654
6864
  text: cachedTextResponse,
6655
6865
  component: null,
6656
- matchedComponents: [],
6657
6866
  actions: conversationMatch.uiBlock?.actions || [],
6658
6867
  reasoning: `Exact match from previous general conversation`,
6659
6868
  method: `${this.getProviderName()}-semantic-match-general`,
@@ -6681,7 +6890,6 @@ ${errorMsg}
6681
6890
  data: {
6682
6891
  text: cachedTextResponse,
6683
6892
  component,
6684
- matchedComponents: component?.props?.config?.components || [],
6685
6893
  actions: cachedActions,
6686
6894
  reasoning: `Exact match from previous conversation (${(conversationMatch.similarity * 100).toFixed(2)}% similarity)`,
6687
6895
  method: `${this.getProviderName()}-semantic-match-exact`,
@@ -6717,7 +6925,6 @@ ${errorMsg}
6717
6925
  data: {
6718
6926
  text: textResponseToUse,
6719
6927
  component: adaptResult.adaptedComponent,
6720
- matchedComponents: adaptResult.adaptedComponent?.props?.config?.components || [],
6721
6928
  actions: cachedActions,
6722
6929
  reasoning: `Adapted from previous conversation: ${originalPrompt}`,
6723
6930
  method: `${this.getProviderName()}-semantic-match`,
@@ -10324,6 +10531,331 @@ function sendResponse8(id, res, sendMessage, clientId) {
10324
10531
  sendMessage(response);
10325
10532
  }
10326
10533
 
10534
+ // src/handlers/menus.ts
10535
+ init_logger();
10536
+ async function handleMenusRequest(data, collections, sendMessage) {
10537
+ const executeCollection = async (collection, op, params) => {
10538
+ const handler = collections[collection]?.[op];
10539
+ if (!handler) {
10540
+ throw new Error(`Collection operation ${collection}.${op} not found`);
10541
+ }
10542
+ return await handler(params);
10543
+ };
10544
+ try {
10545
+ const request = MenusRequestMessageSchema.parse(data);
10546
+ const { id, payload, from } = request;
10547
+ const { operation, data: requestData } = payload;
10548
+ const menuId = requestData?.id;
10549
+ const name = requestData?.name;
10550
+ const componentName = requestData?.componentName;
10551
+ const icon = requestData?.icon;
10552
+ const userMessage = requestData?.userMessage;
10553
+ const parentId = requestData?.parentId;
10554
+ const sortOrder = requestData?.sortOrder;
10555
+ const props = requestData?.props;
10556
+ const isActive = requestData?.isActive;
10557
+ const filters = requestData?.filters;
10558
+ const limit = requestData?.limit;
10559
+ const sort = requestData?.sort;
10560
+ const items = requestData?.items;
10561
+ switch (operation) {
10562
+ case "create":
10563
+ await handleCreate7(id, name, componentName, icon, userMessage, parentId, sortOrder, props, isActive, executeCollection, sendMessage, from.id);
10564
+ break;
10565
+ case "update":
10566
+ await handleUpdate7(id, menuId, name, componentName, icon, userMessage, parentId, sortOrder, props, isActive, executeCollection, sendMessage, from.id);
10567
+ break;
10568
+ case "delete":
10569
+ await handleDelete7(id, menuId, executeCollection, sendMessage, from.id);
10570
+ break;
10571
+ case "getAll":
10572
+ await handleGetAll7(id, executeCollection, sendMessage, from.id);
10573
+ break;
10574
+ case "getOne":
10575
+ await handleGetOne7(id, menuId, executeCollection, sendMessage, from.id);
10576
+ break;
10577
+ case "getRootMenus":
10578
+ await handleGetRootMenus(id, executeCollection, sendMessage, from.id);
10579
+ break;
10580
+ case "getChildMenus":
10581
+ await handleGetChildMenus(id, parentId, executeCollection, sendMessage, from.id);
10582
+ break;
10583
+ case "getHierarchy":
10584
+ await handleGetHierarchy(id, executeCollection, sendMessage, from.id);
10585
+ break;
10586
+ case "query":
10587
+ await handleQuery6(id, filters, limit, sort, executeCollection, sendMessage, from.id);
10588
+ break;
10589
+ case "reorder":
10590
+ await handleReorder(id, items, executeCollection, sendMessage, from.id);
10591
+ break;
10592
+ default:
10593
+ sendResponse9(id, {
10594
+ success: false,
10595
+ error: `Unknown operation: ${operation}`
10596
+ }, sendMessage, from.id);
10597
+ }
10598
+ } catch (error) {
10599
+ logger.error("Failed to handle menus request:", error);
10600
+ sendResponse9(null, {
10601
+ success: false,
10602
+ error: error instanceof Error ? error.message : "Unknown error occurred"
10603
+ }, sendMessage);
10604
+ }
10605
+ }
10606
+ async function handleCreate7(id, name, componentName, icon, userMessage, parentId, sortOrder, props, isActive, executeCollection, sendMessage, clientId) {
10607
+ if (!name) {
10608
+ sendResponse9(id, {
10609
+ success: false,
10610
+ error: "name is required"
10611
+ }, sendMessage, clientId);
10612
+ return;
10613
+ }
10614
+ if (!componentName) {
10615
+ sendResponse9(id, {
10616
+ success: false,
10617
+ error: "componentName is required"
10618
+ }, sendMessage, clientId);
10619
+ return;
10620
+ }
10621
+ try {
10622
+ const result = await executeCollection("menus", "create", {
10623
+ name,
10624
+ componentName,
10625
+ icon,
10626
+ userMessage,
10627
+ parentId,
10628
+ sortOrder,
10629
+ props,
10630
+ isActive
10631
+ });
10632
+ sendResponse9(id, {
10633
+ success: true,
10634
+ data: result.data,
10635
+ message: "Menu created successfully"
10636
+ }, sendMessage, clientId);
10637
+ logger.info(`Menu created: ID ${result.data?.id}`);
10638
+ } catch (error) {
10639
+ sendResponse9(id, {
10640
+ success: false,
10641
+ error: error instanceof Error ? error.message : "Failed to create menu"
10642
+ }, sendMessage, clientId);
10643
+ }
10644
+ }
10645
+ async function handleUpdate7(id, menuId, name, componentName, icon, userMessage, parentId, sortOrder, props, isActive, executeCollection, sendMessage, clientId) {
10646
+ if (!menuId) {
10647
+ sendResponse9(id, {
10648
+ success: false,
10649
+ error: "Menu ID is required"
10650
+ }, sendMessage, clientId);
10651
+ return;
10652
+ }
10653
+ try {
10654
+ const result = await executeCollection("menus", "update", {
10655
+ id: menuId,
10656
+ name,
10657
+ componentName,
10658
+ icon,
10659
+ userMessage,
10660
+ parentId,
10661
+ sortOrder,
10662
+ props,
10663
+ isActive
10664
+ });
10665
+ sendResponse9(id, {
10666
+ success: true,
10667
+ data: result.data,
10668
+ message: "Menu updated successfully"
10669
+ }, sendMessage, clientId);
10670
+ logger.info(`Menu updated: ID ${menuId}`);
10671
+ } catch (error) {
10672
+ sendResponse9(id, {
10673
+ success: false,
10674
+ error: error instanceof Error ? error.message : "Failed to update menu"
10675
+ }, sendMessage, clientId);
10676
+ }
10677
+ }
10678
+ async function handleDelete7(id, menuId, executeCollection, sendMessage, clientId) {
10679
+ if (!menuId) {
10680
+ sendResponse9(id, {
10681
+ success: false,
10682
+ error: "Menu ID is required"
10683
+ }, sendMessage, clientId);
10684
+ return;
10685
+ }
10686
+ try {
10687
+ const result = await executeCollection("menus", "delete", { id: menuId });
10688
+ sendResponse9(id, {
10689
+ success: true,
10690
+ data: result.data,
10691
+ message: "Menu deleted successfully"
10692
+ }, sendMessage, clientId);
10693
+ logger.info(`Menu deleted: ID ${menuId}`);
10694
+ } catch (error) {
10695
+ sendResponse9(id, {
10696
+ success: false,
10697
+ error: error instanceof Error ? error.message : "Failed to delete menu"
10698
+ }, sendMessage, clientId);
10699
+ }
10700
+ }
10701
+ async function handleGetAll7(id, executeCollection, sendMessage, clientId) {
10702
+ try {
10703
+ const result = await executeCollection("menus", "getAll", {});
10704
+ sendResponse9(id, {
10705
+ success: true,
10706
+ data: result.data,
10707
+ count: result.count,
10708
+ message: `Retrieved ${result.count} menus`
10709
+ }, sendMessage, clientId);
10710
+ logger.info(`Retrieved all menus (count: ${result.count})`);
10711
+ } catch (error) {
10712
+ sendResponse9(id, {
10713
+ success: false,
10714
+ error: error instanceof Error ? error.message : "Failed to get menus"
10715
+ }, sendMessage, clientId);
10716
+ }
10717
+ }
10718
+ async function handleGetOne7(id, menuId, executeCollection, sendMessage, clientId) {
10719
+ if (!menuId) {
10720
+ sendResponse9(id, {
10721
+ success: false,
10722
+ error: "Menu ID is required"
10723
+ }, sendMessage, clientId);
10724
+ return;
10725
+ }
10726
+ try {
10727
+ const result = await executeCollection("menus", "getOne", { id: menuId });
10728
+ sendResponse9(id, {
10729
+ success: true,
10730
+ data: result.data,
10731
+ message: `Retrieved menu ID ${menuId}`
10732
+ }, sendMessage, clientId);
10733
+ logger.info(`Retrieved menu: ID ${menuId}`);
10734
+ } catch (error) {
10735
+ sendResponse9(id, {
10736
+ success: false,
10737
+ error: error instanceof Error ? error.message : "Failed to get menu"
10738
+ }, sendMessage, clientId);
10739
+ }
10740
+ }
10741
+ async function handleGetRootMenus(id, executeCollection, sendMessage, clientId) {
10742
+ try {
10743
+ const result = await executeCollection("menus", "getRootMenus", {});
10744
+ sendResponse9(id, {
10745
+ success: true,
10746
+ data: result.data,
10747
+ count: result.count,
10748
+ message: `Retrieved ${result.count} root menus`
10749
+ }, sendMessage, clientId);
10750
+ logger.info(`Retrieved root menus (count: ${result.count})`);
10751
+ } catch (error) {
10752
+ sendResponse9(id, {
10753
+ success: false,
10754
+ error: error instanceof Error ? error.message : "Failed to get root menus"
10755
+ }, sendMessage, clientId);
10756
+ }
10757
+ }
10758
+ async function handleGetChildMenus(id, parentId, executeCollection, sendMessage, clientId) {
10759
+ if (parentId === void 0 || parentId === null) {
10760
+ sendResponse9(id, {
10761
+ success: false,
10762
+ error: "parentId is required"
10763
+ }, sendMessage, clientId);
10764
+ return;
10765
+ }
10766
+ try {
10767
+ const result = await executeCollection("menus", "getChildMenus", { parentId });
10768
+ sendResponse9(id, {
10769
+ success: true,
10770
+ data: result.data,
10771
+ count: result.count,
10772
+ message: `Retrieved ${result.count} child menus for parent ${parentId}`
10773
+ }, sendMessage, clientId);
10774
+ logger.info(`Retrieved child menus for parent ${parentId} (count: ${result.count})`);
10775
+ } catch (error) {
10776
+ sendResponse9(id, {
10777
+ success: false,
10778
+ error: error instanceof Error ? error.message : "Failed to get child menus"
10779
+ }, sendMessage, clientId);
10780
+ }
10781
+ }
10782
+ async function handleGetHierarchy(id, executeCollection, sendMessage, clientId) {
10783
+ try {
10784
+ const result = await executeCollection("menus", "getHierarchy", {});
10785
+ sendResponse9(id, {
10786
+ success: true,
10787
+ data: result.data,
10788
+ count: result.count,
10789
+ message: `Retrieved menus hierarchy with ${result.count} root items`
10790
+ }, sendMessage, clientId);
10791
+ logger.info(`Retrieved menus hierarchy (root count: ${result.count})`);
10792
+ } catch (error) {
10793
+ sendResponse9(id, {
10794
+ success: false,
10795
+ error: error instanceof Error ? error.message : "Failed to get menus hierarchy"
10796
+ }, sendMessage, clientId);
10797
+ }
10798
+ }
10799
+ async function handleQuery6(id, filters, limit, sort, executeCollection, sendMessage, clientId) {
10800
+ try {
10801
+ const result = await executeCollection("menus", "query", {
10802
+ filters: filters || {},
10803
+ limit,
10804
+ sort
10805
+ });
10806
+ sendResponse9(id, {
10807
+ success: true,
10808
+ data: result.data,
10809
+ count: result.count,
10810
+ message: `Query returned ${result.count} menus`
10811
+ }, sendMessage, clientId);
10812
+ logger.info(`Query returned ${result.count} menus`);
10813
+ } catch (error) {
10814
+ sendResponse9(id, {
10815
+ success: false,
10816
+ error: error instanceof Error ? error.message : "Failed to query menus"
10817
+ }, sendMessage, clientId);
10818
+ }
10819
+ }
10820
+ async function handleReorder(id, items, executeCollection, sendMessage, clientId) {
10821
+ if (!items || !Array.isArray(items) || items.length === 0) {
10822
+ sendResponse9(id, {
10823
+ success: false,
10824
+ error: "items array is required"
10825
+ }, sendMessage, clientId);
10826
+ return;
10827
+ }
10828
+ try {
10829
+ const result = await executeCollection("menus", "reorder", { items });
10830
+ sendResponse9(id, {
10831
+ success: true,
10832
+ data: result.data,
10833
+ message: `Reordered ${items.length} menus successfully`
10834
+ }, sendMessage, clientId);
10835
+ logger.info(`Reordered ${items.length} menus`);
10836
+ } catch (error) {
10837
+ sendResponse9(id, {
10838
+ success: false,
10839
+ error: error instanceof Error ? error.message : "Failed to reorder menus"
10840
+ }, sendMessage, clientId);
10841
+ }
10842
+ }
10843
+ function sendResponse9(id, res, sendMessage, clientId) {
10844
+ const response = {
10845
+ id: id || "unknown",
10846
+ type: "MENUS_RES",
10847
+ from: { type: "data-agent" },
10848
+ to: {
10849
+ type: "admin",
10850
+ id: clientId
10851
+ },
10852
+ payload: {
10853
+ ...res
10854
+ }
10855
+ };
10856
+ sendMessage(response);
10857
+ }
10858
+
10327
10859
  // src/dashComp/index.ts
10328
10860
  init_logger();
10329
10861
 
@@ -10450,37 +10982,74 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10450
10982
  return { success: false, errors };
10451
10983
  }
10452
10984
  logger.info(`[DASH_COMP_REQ] Using model: ${model}`);
10453
- const result = await LLM.stream(
10985
+ const executedTools = [];
10986
+ const llmTools = (tools || []).map((tool) => ({
10987
+ name: tool.id,
10988
+ description: tool.description,
10989
+ input_schema: {
10990
+ type: "object",
10991
+ properties: Object.fromEntries(
10992
+ Object.entries(tool.params || {}).map(([key, val]) => [key, { type: typeof val === "string" && ["string", "number", "boolean", "integer"].includes(val.toLowerCase()) ? val.toLowerCase() : "string", description: `${key} parameter` }])
10993
+ ),
10994
+ additionalProperties: false
10995
+ }
10996
+ }));
10997
+ const toolHandler = async (toolName, toolInput) => {
10998
+ const tool = tools?.find((t) => t.id === toolName);
10999
+ if (!tool) {
11000
+ throw new Error(`Unknown tool: ${toolName}`);
11001
+ }
11002
+ logger.info(`[DASH_COMP_REQ] Executing external tool: ${tool.name} (${tool.id})`);
11003
+ const result2 = await tool.fn(toolInput);
11004
+ executedTools.push({
11005
+ id: tool.id,
11006
+ name: tool.name,
11007
+ params: toolInput,
11008
+ result: result2,
11009
+ outputSchema: tool.outputSchema
11010
+ });
11011
+ logger.info(`[DASH_COMP_REQ] Tool ${tool.name} executed successfully`);
11012
+ return JSON.stringify(result2, null, 2);
11013
+ };
11014
+ const result = await LLM.streamWithTools(
10454
11015
  {
10455
11016
  sys: prompts.system,
10456
11017
  user: prompts.user
10457
11018
  },
11019
+ llmTools,
11020
+ toolHandler,
10458
11021
  {
10459
11022
  model,
10460
11023
  maxTokens: 8192,
10461
11024
  temperature: 0.2,
10462
11025
  apiKey
10463
11026
  },
10464
- true
10465
- // Parse as JSON
11027
+ 5
11028
+ // max iterations
10466
11029
  );
11030
+ const jsonMatch = result.match(/\{[\s\S]*\}/);
11031
+ const parsedResult = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
11032
+ if (!parsedResult) {
11033
+ errors.push("Failed to parse LLM response as JSON");
11034
+ return { success: false, errors };
11035
+ }
10467
11036
  logger.debug("[DASH_COMP_REQ] LLM response received");
10468
- logger.file("[DASH_COMP_REQ] LLM response:", JSON.stringify(result, null, 2));
10469
- if (!result.componentId || !result.props) {
11037
+ logger.file("[DASH_COMP_REQ] LLM response:", JSON.stringify(parsedResult, null, 2));
11038
+ if (!parsedResult.componentId || !parsedResult.props) {
10470
11039
  errors.push("Invalid LLM response: missing componentId or props");
10471
11040
  userPromptErrorLogger.logError("DASH_COMP_REQ", "Invalid LLM response structure", {
10472
11041
  prompt,
10473
- result,
10474
- missingFields: { componentId: !result.componentId, props: !result.props }
11042
+ result: parsedResult,
11043
+ missingFields: { componentId: !parsedResult.componentId, props: !parsedResult.props }
10475
11044
  });
10476
11045
  return { success: false, errors };
10477
11046
  }
10478
- const originalComponent = components.find((c) => c.name === result.componentName);
11047
+ const originalComponent = components.find((c) => c.name === parsedResult.componentName);
10479
11048
  if (!originalComponent) {
10480
- errors.push(`Component ${result.componentName} not found in available components`);
11049
+ errors.push(`Component ${parsedResult.componentName} not found in available components`);
10481
11050
  userPromptErrorLogger.logError("DASH_COMP_REQ", "Component not found", {
10482
11051
  prompt,
10483
- componentName: result.componentName,
11052
+ componentName: parsedResult.componentName,
10484
11053
  availableComponentNames: components.map((c) => c.name)
10485
11054
  });
10486
11055
  return { success: false, errors };
@@ -10489,23 +11058,27 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10489
11058
  ...originalComponent,
10490
11059
  props: {
10491
11060
  ...originalComponent.props,
10492
- ...result.props
11061
+ ...parsedResult.props
10493
11062
  }
10494
11063
  };
10495
11064
  logger.info(`[DASH_COMP_REQ] Successfully picked component: ${finalComponent.name} (${finalComponent.type})`);
10496
- if (result.props.query) {
11065
+ if (parsedResult.props.query) {
10497
11066
  logger.info(`[DASH_COMP_REQ] Data source: Database query`);
10498
11067
  }
10499
- if (result.props.externalTool) {
10500
- logger.info(`[DASH_COMP_REQ] Data source: External tool - ${result.props.externalTool.toolName}`);
11068
+ if (parsedResult.props.externalTool) {
11069
+ logger.info(`[DASH_COMP_REQ] Data source: External tool - ${parsedResult.props.externalTool.toolName}`);
11070
+ }
11071
+ if (executedTools.length > 0) {
11072
+ logger.info(`[DASH_COMP_REQ] Executed ${executedTools.length} external tool(s): ${executedTools.map((t) => t.name).join(", ")}`);
10501
11073
  }
10502
11074
  return {
10503
11075
  success: true,
10504
11076
  data: {
10505
11077
  component: finalComponent,
10506
- reasoning: result.reasoning || "Component selected based on user prompt",
10507
- dataSource: result.props.query ? "database" : result.props.externalTool ? "external_tool" : "none",
10508
- isUpdate: result.isUpdate || false
11078
+ reasoning: parsedResult.reasoning || "Component selected based on user prompt",
11079
+ dataSource: parsedResult.props.query ? "database" : parsedResult.props.externalTool ? "external_tool" : "none",
11080
+ isUpdate: parsedResult.isUpdate || false,
11081
+ executedTools: executedTools.length > 0 ? executedTools : void 0
10509
11082
  },
10510
11083
  errors: []
10511
11084
  };
@@ -10558,11 +11131,49 @@ async function createFilterWithLLM(prompt, components, existingComponents, anthr
10558
11131
  return { success: false, errors };
10559
11132
  }
10560
11133
  logger.info(`[DASH_COMP_REQ:FILTER] Using model: ${model}`);
10561
- const result = await LLM.stream(
11134
+ const executedTools = [];
11135
+ const llmTools = (tools || []).map((tool) => ({
11136
+ name: tool.id,
11137
+ description: tool.description,
11138
+ input_schema: {
11139
+ type: "object",
11140
+ properties: Object.fromEntries(
11141
+ Object.entries(tool.params || {}).map(([key, val]) => [key, { type: typeof val === "string" && ["string", "number", "boolean", "integer"].includes(val.toLowerCase()) ? val.toLowerCase() : "string", description: `${key} parameter` }])
11142
+ ),
11143
+ additionalProperties: false
11144
+ }
11145
+ }));
11146
+ const toolHandler = async (toolName, toolInput) => {
11147
+ const tool = tools?.find((t) => t.id === toolName);
11148
+ if (!tool) {
11149
+ throw new Error(`Unknown tool: ${toolName}`);
11150
+ }
11151
+ logger.info(`[DASH_COMP_REQ:FILTER] Executing external tool: ${tool.name} (${tool.id})`);
11152
+ const result2 = await tool.fn(toolInput);
11153
+ executedTools.push({
11154
+ id: tool.id,
11155
+ name: tool.name,
11156
+ params: toolInput,
11157
+ result: result2,
11158
+ outputSchema: tool.outputSchema
11159
+ });
11160
+ logger.info(`[DASH_COMP_REQ:FILTER] Tool ${tool.name} executed successfully`);
11161
+ return JSON.stringify(result2, null, 2);
11162
+ };
11163
+ const rawResult = await LLM.streamWithTools(
10562
11164
  { sys: prompts.system, user: prompts.user },
11165
+ llmTools,
11166
+ toolHandler,
10563
11167
  { model, maxTokens: 16384, temperature: 0.2, apiKey },
10564
- true
11168
+ 5
11169
+ // max iterations
10565
11170
  );
11171
+ const jsonMatch = rawResult.match(/\{[\s\S]*\}/);
11172
+ const result = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
11173
+ if (!result) {
11174
+ errors.push("Failed to parse LLM response as JSON");
11175
+ return { success: false, errors };
11176
+ }
10566
11177
  logger.debug("[DASH_COMP_REQ:FILTER] LLM response received");
10567
11178
  logger.file("[DASH_COMP_REQ:FILTER] LLM response:", JSON.stringify(result, null, 2));
10568
11179
  if (!result.filterComponent) {
@@ -10576,13 +11187,17 @@ async function createFilterWithLLM(prompt, components, existingComponents, anthr
10576
11187
  }
10577
11188
  logger.info(`[DASH_COMP_REQ:FILTER] Successfully created filter: ${result.filterComponent.componentType}`);
10578
11189
  logger.info(`[DASH_COMP_REQ:FILTER] Updated ${result.updatedComponents?.length || 0} components`);
11190
+ if (executedTools.length > 0) {
11191
+ logger.info(`[DASH_COMP_REQ:FILTER] Executed ${executedTools.length} external tool(s): ${executedTools.map((t) => t.name).join(", ")}`);
11192
+ }
10579
11193
  return {
10580
11194
  success: true,
10581
11195
  data: {
10582
11196
  filterComponent: result.filterComponent,
10583
11197
  updatedComponents: result.updatedComponents || [],
10584
11198
  filterBindings: result.filterBindings || {},
10585
- reasoning: result.reasoning || "Filter created based on user prompt"
11199
+ reasoning: result.reasoning || "Filter created based on user prompt",
11200
+ executedTools: executedTools.length > 0 ? executedTools : void 0
10586
11201
  },
10587
11202
  errors: []
10588
11203
  };
@@ -11760,6 +12375,11 @@ var SuperatomSDK = class {
11760
12375
  logger.error("Failed to handle KB nodes request:", error);
11761
12376
  });
11762
12377
  break;
12378
+ case "MENUS":
12379
+ handleMenusRequest(parsed, this.collections, (msg) => this.send(msg)).catch((error) => {
12380
+ logger.error("Failed to handle menus request:", error);
12381
+ });
12382
+ break;
11763
12383
  case "DASH_COMP_REQ":
11764
12384
  handleDashCompRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.geminiApiKey, this.openaiApiKey, this.llmProviders, this.collections, this.tools).catch((error) => {
11765
12385
  logger.error("Failed to handle dash comp request:", error);