@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.js CHANGED
@@ -31,13 +31,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
33
  // src/utils/logger.ts
34
- var import_fs, PREFIX, LOGSTREAM, LOG_LEVEL_PRIORITY, MESSAGE_LEVEL_PRIORITY, Logger, logger;
34
+ var import_fs, PREFIX, LOG_FILE_PATH, LOGSTREAM, LOG_LEVEL_PRIORITY, MESSAGE_LEVEL_PRIORITY, Logger, logger;
35
35
  var init_logger = __esm({
36
36
  "src/utils/logger.ts"() {
37
37
  "use strict";
38
38
  import_fs = __toESM(require("fs"));
39
39
  PREFIX = "[SuperatomSDK]";
40
- LOGSTREAM = import_fs.default.createWriteStream("superatom-sdk.log", { flags: "a" });
40
+ LOG_FILE_PATH = "superatom-sdk.log";
41
+ LOGSTREAM = import_fs.default.createWriteStream(LOG_FILE_PATH, { flags: "a" });
41
42
  LOG_LEVEL_PRIORITY = {
42
43
  errors: 0,
43
44
  warnings: 1,
@@ -121,9 +122,43 @@ var init_logger = __esm({
121
122
  console.log(PREFIX, "[DEBUG]", ...args);
122
123
  }
123
124
  }
125
+ /**
126
+ * Write to log file
127
+ */
124
128
  file(...args) {
125
129
  LOGSTREAM.write(args.join(" ") + "\n");
126
130
  }
131
+ /**
132
+ * Clear the log file (call at start of new user request)
133
+ */
134
+ clearFile() {
135
+ LOGSTREAM.end();
136
+ LOGSTREAM = import_fs.default.createWriteStream(LOG_FILE_PATH, { flags: "w" });
137
+ LOGSTREAM.write(`
138
+ ${"=".repeat(80)}
139
+ `);
140
+ LOGSTREAM.write(`NEW REQUEST - ${(/* @__PURE__ */ new Date()).toISOString()}
141
+ `);
142
+ LOGSTREAM.write(`${"=".repeat(80)}
143
+
144
+ `);
145
+ }
146
+ /**
147
+ * Log LLM method prompts with clear labeling
148
+ */
149
+ logLLMPrompt(methodName, promptType, content) {
150
+ const header = `
151
+ ${"#".repeat(80)}
152
+ [LLM METHOD: ${methodName}] - ${promptType.toUpperCase()} PROMPT
153
+ ${"#".repeat(80)}
154
+ `;
155
+ LOGSTREAM.write(header);
156
+ LOGSTREAM.write(content);
157
+ LOGSTREAM.write(`
158
+ ${"#".repeat(80)}
159
+
160
+ `);
161
+ }
127
162
  };
128
163
  logger = new Logger();
129
164
  }
@@ -1041,8 +1076,20 @@ If adaptation is not possible or would fundamentally change the component:
1041
1076
 
1042
1077
  Analyze the user's request and:
1043
1078
  1. **Select the most appropriate component** from the available components list
1044
- 2. **Determine the data source**: Database query OR External tool (ERP)
1045
- 3. **Generate complete props** for the selected component including the data retrieval/modification method
1079
+ 2. **Determine the data source**: Database query OR External tool
1080
+ 3. **Generate complete props** for the selected component
1081
+
1082
+ ## Available External Tools
1083
+
1084
+ The following external tools are available:
1085
+
1086
+ {{AVAILABLE_TOOLS}}
1087
+
1088
+ When a tool is needed to complete the user's request:
1089
+ 1. **Analyze the request** to determine which tool is needed
1090
+ 2. **Extract parameters** from the user's question
1091
+ 3. **Execute the tool** by calling it with the extracted parameters
1092
+ 4. **Use the results** to configure the component (field names for axes, columns, etc.)
1046
1093
 
1047
1094
  ## Component Selection Rules
1048
1095
 
@@ -1198,7 +1245,20 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1198
1245
 
1199
1246
  1. **Create a filter component** based on the user's request
1200
1247
  2. **Update existing components** with dynamic title/description interpolation if needed
1201
- 3. **Preserve all existing props** - the filter system handles param merging at runtime
1248
+ 3. **Set default values in component externalTool.params** that match the filter's default option
1249
+ 4. **Preserve all existing props** - the filter system handles param merging at runtime
1250
+
1251
+ ## Available External Tools
1252
+
1253
+ The following external tools are available:
1254
+
1255
+ {{AVAILABLE_TOOLS}}
1256
+
1257
+ When a tool is needed to complete the user's request:
1258
+ 1. **Analyze the request** to determine which tool is needed
1259
+ 2. **Extract parameters** from the user's question
1260
+ 3. **Execute the tool** by calling it with the extracted parameters
1261
+ 4. **Use the results** to configure the filter and components properly
1202
1262
 
1203
1263
  ## How The Filter System Works
1204
1264
 
@@ -1228,16 +1288,20 @@ Use \`{%filterKeyLabel%}\` syntax for dynamic text:
1228
1288
  ## Updating Existing Components
1229
1289
 
1230
1290
  **IMPORTANT - Parameter Handling:**
1231
- - Do NOT change existing parameter values to placeholders
1232
- - Keep all existing/default parameter values as they are
1233
1291
  - The filter system MERGES params at runtime: filter params override component defaults
1292
+ - Component's \`externalTool.params\` should have DEFAULT values matching the filter's default option
1293
+ - This ensures the component shows correct data on initial load before user changes the filter
1234
1294
 
1235
1295
  **What to modify in existing components:**
1236
1296
  - Modify \`title\` for \`{%filterKeyLabel%}\` interpolation (only if title exists)
1237
1297
  - Modify \`description\` for interpolation (only if description exists)
1238
- - Modify other props only if specifically needed for the filter to function
1298
+ - Set \`externalTool.params\` default values to match filter's default option params
1239
1299
  - Copy ALL other props exactly as provided
1240
1300
 
1301
+ **Example - Setting default params:**
1302
+ If filter has default option with params: \`{ startDate: "2025-01-01", endDate: "2025-01-31" }\`
1303
+ Then component's externalTool should have: \`{ params: { startDate: "2025-01-01", endDate: "2025-01-31" } }\`
1304
+
1241
1305
  ### Database Query Rules
1242
1306
  {{DATABASE_RULES}}
1243
1307
 
@@ -1285,10 +1349,11 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1285
1349
  **CRITICAL RULES:**
1286
1350
  1. Return ONLY valid JSON (no markdown code blocks)
1287
1351
  2. **COPY ALL existing props** - modify title/description for interpolation only if they exist
1288
- 3. **DO NOT change parameter values** - keep existing defaults, filter merges at runtime
1352
+ 3. **Set externalTool.params defaults** to match the filter's default option params
1289
1353
  4. Use \`{%filterKeyLabel%}\` for dynamic text (NOT \`{{...}}\` or \`$...\`)
1290
1354
  5. Filter \`params\` must have ACTUAL values (real dates, strings), not placeholders
1291
1355
  6. Each filter option needs: label, value, params (and optionally isDefault)
1356
+ 7. Component default params MUST match filter default - this ensures correct initial data load
1292
1357
 
1293
1358
  ## Database Schema
1294
1359
  {{SCHEMA_DOC}}
@@ -2359,6 +2424,57 @@ var KbNodesRequestMessageSchema = import_zod3.z.object({
2359
2424
  type: import_zod3.z.literal("KB_NODES"),
2360
2425
  payload: KbNodesRequestPayloadSchema
2361
2426
  });
2427
+ var MenusQueryFiltersSchema = import_zod3.z.object({
2428
+ parentId: import_zod3.z.number().nullable().optional(),
2429
+ isActive: import_zod3.z.boolean().optional()
2430
+ });
2431
+ var MenusRequestPayloadSchema = import_zod3.z.object({
2432
+ operation: import_zod3.z.enum([
2433
+ "create",
2434
+ "update",
2435
+ "delete",
2436
+ "getAll",
2437
+ "getOne",
2438
+ "getRootMenus",
2439
+ "getChildMenus",
2440
+ "getHierarchy",
2441
+ "query",
2442
+ "reorder"
2443
+ ]),
2444
+ data: import_zod3.z.object({
2445
+ id: import_zod3.z.number().optional(),
2446
+ name: import_zod3.z.string().optional(),
2447
+ componentName: import_zod3.z.string().optional(),
2448
+ icon: import_zod3.z.string().optional(),
2449
+ userMessage: import_zod3.z.string().optional(),
2450
+ parentId: import_zod3.z.number().nullable().optional(),
2451
+ sortOrder: import_zod3.z.number().optional(),
2452
+ props: import_zod3.z.record(import_zod3.z.unknown()).optional(),
2453
+ isActive: import_zod3.z.boolean().optional(),
2454
+ // Query operation fields
2455
+ filters: MenusQueryFiltersSchema.optional(),
2456
+ limit: import_zod3.z.number().optional(),
2457
+ sort: import_zod3.z.enum(["ASC", "DESC"]).optional(),
2458
+ // Reorder operation fields
2459
+ items: import_zod3.z.array(import_zod3.z.object({
2460
+ id: import_zod3.z.number(),
2461
+ sortOrder: import_zod3.z.number()
2462
+ })).optional()
2463
+ }).optional()
2464
+ });
2465
+ var MenusRequestMessageSchema = import_zod3.z.object({
2466
+ id: import_zod3.z.string(),
2467
+ from: MessageParticipantSchema,
2468
+ type: import_zod3.z.literal("MENUS"),
2469
+ payload: MenusRequestPayloadSchema
2470
+ });
2471
+ var MenusResponsePayloadSchema = import_zod3.z.object({
2472
+ success: import_zod3.z.boolean(),
2473
+ error: import_zod3.z.string().optional(),
2474
+ data: import_zod3.z.any().optional(),
2475
+ count: import_zod3.z.number().optional(),
2476
+ message: import_zod3.z.string().optional()
2477
+ });
2362
2478
  var DashCompRequestPayloadSchema = import_zod3.z.object({
2363
2479
  prompt: import_zod3.z.string(),
2364
2480
  userId: import_zod3.z.string().optional(),
@@ -5719,30 +5835,35 @@ ${JSON.stringify(tool.requiredFields || [], null, 2)}`;
5719
5835
  let executedToolsText = "No external tools were executed for data fetching.";
5720
5836
  if (executedTools && executedTools.length > 0) {
5721
5837
  logger.info(`[${this.getProviderName()}] Passing ${executedTools.length} executed tools to component matching`);
5722
- 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) => {
5838
+ 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) => {
5723
5839
  let outputSchemaText = "Not available";
5840
+ let fieldNamesList = "";
5724
5841
  let recordCount = "unknown";
5725
5842
  if (tool.outputSchema) {
5726
5843
  const fields = tool.outputSchema.fields || [];
5727
5844
  recordCount = tool.result?._recordCount || (Array.isArray(tool.result) ? tool.result.length : "unknown");
5845
+ const numericFields = fields.filter((f) => f.type === "number").map((f) => f.name);
5846
+ const stringFields = fields.filter((f) => f.type === "string").map((f) => f.name);
5847
+ fieldNamesList = `
5848
+ \u{1F4CA} NUMERIC FIELDS (use for yAxisKey, valueKey, aggregationField): ${numericFields.join(", ") || "none"}
5849
+ \u{1F4DD} STRING FIELDS (use for xAxisKey, groupBy, nameKey): ${stringFields.join(", ") || "none"}`;
5850
+ const fieldsText = fields.map(
5851
+ (f) => ` "${f.name}" (${f.type}): ${f.description}`
5852
+ ).join("\n");
5728
5853
  outputSchemaText = `${tool.outputSchema.description}
5729
- Fields in EACH ROW (per-row values, NOT aggregates):
5730
- ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")}`;
5854
+ Fields:
5855
+ ${fieldsText}`;
5731
5856
  }
5732
5857
  return `${idx + 1}. **${tool.name}**
5733
- toolId: "${tool.id}" (USE THIS EXACT VALUE for externalTool.toolId)
5734
- toolName: "${tool.name}" (USE THIS EXACT VALUE for externalTool.toolName)
5735
- parameters: ${JSON.stringify(tool.params || {})} (USE THESE for externalTool.parameters)
5858
+ toolId: "${tool.id}"
5859
+ toolName: "${tool.name}"
5860
+ parameters: ${JSON.stringify(tool.params || {})}
5736
5861
  recordCount: ${recordCount} rows returned
5737
- outputSchema: ${outputSchemaText}
5738
- \u26A0\uFE0F DO NOT embed this tool's data in SQL - use externalTool prop OR query database tables`;
5862
+ outputSchema: ${outputSchemaText}${fieldNamesList}`;
5739
5863
  }).join("\n\n");
5740
5864
  }
5741
5865
  const schemaDoc = schema.generateSchemaDocumentation();
5742
5866
  const databaseRules = await promptLoader.loadDatabaseRules();
5743
- logger.file("\n=============================\nText analysis response:", analysisContent);
5744
- logger.file("\n=============================\nDeferred tools:", deferredToolsText);
5745
- logger.file("\n=============================\nExecuted tools:", executedToolsText);
5746
5867
  const prompts = await promptLoader.loadPrompts("match-text-components", {
5747
5868
  ANALYSIS_CONTENT: analysisContent,
5748
5869
  AVAILABLE_COMPONENTS: availableComponentsText,
@@ -5752,7 +5873,13 @@ ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")
5752
5873
  EXECUTED_TOOLS: executedToolsText
5753
5874
  });
5754
5875
  logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
5755
- logger.file("\n=============================\nmatch text components system prompt:", prompts.system);
5876
+ const systemPromptStr = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
5877
+ logger.logLLMPrompt("matchComponentsFromAnalysis", "system", systemPromptStr);
5878
+ logger.logLLMPrompt("matchComponentsFromAnalysis", "user", `Text Analysis:
5879
+ ${analysisContent}
5880
+
5881
+ Executed Tools:
5882
+ ${executedToolsText}`);
5756
5883
  logCollector?.info("Matching components from text response...");
5757
5884
  let fullResponseText = "";
5758
5885
  let answerComponentExtracted = false;
@@ -5884,6 +6011,85 @@ ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")
5884
6011
  if (!isValidTool) {
5885
6012
  logger.warn(`[${this.getProviderName()}] externalTool.toolId "${toolId}" not found in executed tools [${validToolIds.join(", ")}], setting to null`);
5886
6013
  cleanedProps.externalTool = null;
6014
+ } else {
6015
+ const executedTool = executedTools?.find((t) => t.id === toolId);
6016
+ if (executedTool?.outputSchema?.fields && cleanedProps.config) {
6017
+ const validFieldNames = executedTool.outputSchema.fields.map((f) => f.name);
6018
+ const validFieldNamesLower = validFieldNames.map((n) => n.toLowerCase());
6019
+ const findMatchingField = (fieldName, configKey) => {
6020
+ if (!fieldName) return null;
6021
+ const lowerField = fieldName.toLowerCase();
6022
+ const exactIdx = validFieldNamesLower.indexOf(lowerField);
6023
+ if (exactIdx !== -1) return validFieldNames[exactIdx];
6024
+ const containsMatches = validFieldNames.filter(
6025
+ (_, i) => validFieldNamesLower[i].includes(lowerField) || lowerField.includes(validFieldNamesLower[i])
6026
+ );
6027
+ if (containsMatches.length === 1) return containsMatches[0];
6028
+ const fieldTypes = executedTool.outputSchema.fields.reduce((acc, f) => {
6029
+ acc[f.name] = f.type;
6030
+ return acc;
6031
+ }, {});
6032
+ const numericConfigKeys = ["yAxisKey", "valueKey", "aggregationField", "sizeKey"];
6033
+ const stringConfigKeys = ["xAxisKey", "nameKey", "labelKey", "groupBy"];
6034
+ if (numericConfigKeys.includes(configKey)) {
6035
+ const numericFields = validFieldNames.filter((f) => fieldTypes[f] === "number");
6036
+ const match = numericFields.find((f) => f.toLowerCase().includes(lowerField) || lowerField.includes(f.toLowerCase()));
6037
+ if (match) return match;
6038
+ if (numericFields.length > 0) {
6039
+ logger.warn(`[${this.getProviderName()}] No match for "${fieldName}", using first numeric field: ${numericFields[0]}`);
6040
+ return numericFields[0];
6041
+ }
6042
+ }
6043
+ if (stringConfigKeys.includes(configKey)) {
6044
+ const stringFields = validFieldNames.filter((f) => fieldTypes[f] === "string");
6045
+ const match = stringFields.find((f) => f.toLowerCase().includes(lowerField) || lowerField.includes(f.toLowerCase()));
6046
+ if (match) return match;
6047
+ if (stringFields.length > 0) {
6048
+ logger.warn(`[${this.getProviderName()}] No match for "${fieldName}", using first string field: ${stringFields[0]}`);
6049
+ return stringFields[0];
6050
+ }
6051
+ }
6052
+ logger.warn(`[${this.getProviderName()}] No match for "${fieldName}", using first field: ${validFieldNames[0]}`);
6053
+ return validFieldNames[0];
6054
+ };
6055
+ const configFieldsToValidate = [
6056
+ "xAxisKey",
6057
+ "yAxisKey",
6058
+ "valueKey",
6059
+ "nameKey",
6060
+ "labelKey",
6061
+ "groupBy",
6062
+ "aggregationField",
6063
+ "seriesKey",
6064
+ "sizeKey",
6065
+ "xAggregationField",
6066
+ "yAggregationField"
6067
+ ];
6068
+ for (const configKey of configFieldsToValidate) {
6069
+ const fieldValue = cleanedProps.config[configKey];
6070
+ if (fieldValue && typeof fieldValue === "string") {
6071
+ if (!validFieldNames.includes(fieldValue)) {
6072
+ const correctedField = findMatchingField(fieldValue, configKey);
6073
+ if (correctedField) {
6074
+ logger.warn(`[${this.getProviderName()}] Correcting config.${configKey}: "${fieldValue}" \u2192 "${correctedField}"`);
6075
+ cleanedProps.config[configKey] = correctedField;
6076
+ }
6077
+ }
6078
+ }
6079
+ }
6080
+ if (Array.isArray(cleanedProps.config.series)) {
6081
+ cleanedProps.config.series = cleanedProps.config.series.map((s) => {
6082
+ if (s.dataKey && typeof s.dataKey === "string" && !validFieldNames.includes(s.dataKey)) {
6083
+ const correctedField = findMatchingField(s.dataKey, "yAxisKey");
6084
+ if (correctedField) {
6085
+ logger.warn(`[${this.getProviderName()}] Correcting series.dataKey: "${s.dataKey}" \u2192 "${correctedField}"`);
6086
+ return { ...s, dataKey: correctedField };
6087
+ }
6088
+ }
6089
+ return s;
6090
+ });
6091
+ }
6092
+ }
5887
6093
  }
5888
6094
  }
5889
6095
  if (cleanedProps.query) {
@@ -5941,6 +6147,10 @@ ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")
5941
6147
  AVAILABLE_TOOLS: availableToolsDoc,
5942
6148
  SCHEMA_DOC: schemaDoc || "No database schema available"
5943
6149
  });
6150
+ const systemPrompt = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
6151
+ const userPromptText = Array.isArray(prompts.user) ? prompts.user.join("\n") : prompts.user;
6152
+ logger.logLLMPrompt("classifyQuestionCategory", "system", systemPrompt);
6153
+ logger.logLLMPrompt("classifyQuestionCategory", "user", userPromptText);
5944
6154
  const result = await LLM.stream(
5945
6155
  {
5946
6156
  sys: prompts.system,
@@ -6128,7 +6338,6 @@ ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")
6128
6338
  collections,
6129
6339
  topK: 1
6130
6340
  });
6131
- logger.file("\n=============================\nknowledge base context:", knowledgeBaseContext);
6132
6341
  const prompts = await promptLoader.loadPrompts("text-response", {
6133
6342
  USER_PROMPT: userPrompt,
6134
6343
  CONVERSATION_HISTORY: conversationHistory || "No previous conversation",
@@ -6137,8 +6346,10 @@ ${fields.map((f) => ` - ${f.name} (${f.type}): ${f.description}`).join("\n")
6137
6346
  KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext || "No additional knowledge base context available.",
6138
6347
  AVAILABLE_EXTERNAL_TOOLS: availableToolsDoc
6139
6348
  });
6140
- logger.file("\n=============================\nsystem prompt:", prompts.system);
6141
- logger.file("\n=============================\nuser prompt:", prompts.user);
6349
+ const sysPrompt = Array.isArray(prompts.system) ? prompts.system.join("\n") : prompts.system;
6350
+ const usrPrompt = Array.isArray(prompts.user) ? prompts.user.join("\n") : prompts.user;
6351
+ logger.logLLMPrompt("generateTextResponse", "system", sysPrompt);
6352
+ logger.logLLMPrompt("generateTextResponse", "user", usrPrompt);
6142
6353
  logger.debug(`[${this.getProviderName()}] Loaded text-response prompts with schema`);
6143
6354
  logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
6144
6355
  logCollector?.info("Generating text response with query execution capability...");
@@ -6524,7 +6735,6 @@ ${errorMsg}
6524
6735
  data: {
6525
6736
  text: textResponse,
6526
6737
  // Include the streamed text showing all attempts
6527
- matchedComponents: [],
6528
6738
  actions: [],
6529
6739
  method: `${this.getProviderName()}-text-response-max-attempts`
6530
6740
  }
@@ -6622,7 +6832,6 @@ ${errorMsg}
6622
6832
  success: true,
6623
6833
  data: {
6624
6834
  text: textResponse,
6625
- matchedComponents,
6626
6835
  component: container_componet,
6627
6836
  actions,
6628
6837
  method: `${this.getProviderName()}-text-response`
@@ -6646,7 +6855,6 @@ ${errorMsg}
6646
6855
  errors,
6647
6856
  data: {
6648
6857
  text: "I apologize, but I encountered an error while processing your question. Please try rephrasing or ask something else.",
6649
- matchedComponents: [],
6650
6858
  actions: [],
6651
6859
  method: `${this.getProviderName()}-text-response-error`
6652
6860
  }
@@ -6670,6 +6878,8 @@ ${errorMsg}
6670
6878
  const startTime = Date.now();
6671
6879
  logger.info(`[${this.getProviderName()}] handleUserRequest called for user prompt: ${userPrompt}`);
6672
6880
  logCollector?.info(`Starting request processing with mode: ${responseMode}`);
6881
+ logger.clearFile();
6882
+ logger.logLLMPrompt("handleUserRequest", "user", `User Prompt: ${userPrompt}`);
6673
6883
  try {
6674
6884
  logger.info(`[${this.getProviderName()}] Step 1: Searching previous conversations...`);
6675
6885
  logCollector?.info("Step 1: Searching for similar previous conversations...");
@@ -6677,8 +6887,8 @@ ${errorMsg}
6677
6887
  userPrompt,
6678
6888
  collections,
6679
6889
  userId,
6680
- similarityThreshold: 0.75
6681
- // 75% threshold
6890
+ similarityThreshold: 0.8
6891
+ // 80% threshold
6682
6892
  });
6683
6893
  if (conversationMatch) {
6684
6894
  logger.info(`[${this.getProviderName()}] \u2713 Found matching conversation with ${(conversationMatch.similarity * 100).toFixed(2)}% similarity`);
@@ -6703,7 +6913,6 @@ ${errorMsg}
6703
6913
  data: {
6704
6914
  text: cachedTextResponse,
6705
6915
  component: null,
6706
- matchedComponents: [],
6707
6916
  actions: conversationMatch.uiBlock?.actions || [],
6708
6917
  reasoning: `Exact match from previous general conversation`,
6709
6918
  method: `${this.getProviderName()}-semantic-match-general`,
@@ -6731,7 +6940,6 @@ ${errorMsg}
6731
6940
  data: {
6732
6941
  text: cachedTextResponse,
6733
6942
  component,
6734
- matchedComponents: component?.props?.config?.components || [],
6735
6943
  actions: cachedActions,
6736
6944
  reasoning: `Exact match from previous conversation (${(conversationMatch.similarity * 100).toFixed(2)}% similarity)`,
6737
6945
  method: `${this.getProviderName()}-semantic-match-exact`,
@@ -6767,7 +6975,6 @@ ${errorMsg}
6767
6975
  data: {
6768
6976
  text: textResponseToUse,
6769
6977
  component: adaptResult.adaptedComponent,
6770
- matchedComponents: adaptResult.adaptedComponent?.props?.config?.components || [],
6771
6978
  actions: cachedActions,
6772
6979
  reasoning: `Adapted from previous conversation: ${originalPrompt}`,
6773
6980
  method: `${this.getProviderName()}-semantic-match`,
@@ -10374,6 +10581,331 @@ function sendResponse8(id, res, sendMessage, clientId) {
10374
10581
  sendMessage(response);
10375
10582
  }
10376
10583
 
10584
+ // src/handlers/menus.ts
10585
+ init_logger();
10586
+ async function handleMenusRequest(data, collections, sendMessage) {
10587
+ const executeCollection = async (collection, op, params) => {
10588
+ const handler = collections[collection]?.[op];
10589
+ if (!handler) {
10590
+ throw new Error(`Collection operation ${collection}.${op} not found`);
10591
+ }
10592
+ return await handler(params);
10593
+ };
10594
+ try {
10595
+ const request = MenusRequestMessageSchema.parse(data);
10596
+ const { id, payload, from } = request;
10597
+ const { operation, data: requestData } = payload;
10598
+ const menuId = requestData?.id;
10599
+ const name = requestData?.name;
10600
+ const componentName = requestData?.componentName;
10601
+ const icon = requestData?.icon;
10602
+ const userMessage = requestData?.userMessage;
10603
+ const parentId = requestData?.parentId;
10604
+ const sortOrder = requestData?.sortOrder;
10605
+ const props = requestData?.props;
10606
+ const isActive = requestData?.isActive;
10607
+ const filters = requestData?.filters;
10608
+ const limit = requestData?.limit;
10609
+ const sort = requestData?.sort;
10610
+ const items = requestData?.items;
10611
+ switch (operation) {
10612
+ case "create":
10613
+ await handleCreate7(id, name, componentName, icon, userMessage, parentId, sortOrder, props, isActive, executeCollection, sendMessage, from.id);
10614
+ break;
10615
+ case "update":
10616
+ await handleUpdate7(id, menuId, name, componentName, icon, userMessage, parentId, sortOrder, props, isActive, executeCollection, sendMessage, from.id);
10617
+ break;
10618
+ case "delete":
10619
+ await handleDelete7(id, menuId, executeCollection, sendMessage, from.id);
10620
+ break;
10621
+ case "getAll":
10622
+ await handleGetAll7(id, executeCollection, sendMessage, from.id);
10623
+ break;
10624
+ case "getOne":
10625
+ await handleGetOne7(id, menuId, executeCollection, sendMessage, from.id);
10626
+ break;
10627
+ case "getRootMenus":
10628
+ await handleGetRootMenus(id, executeCollection, sendMessage, from.id);
10629
+ break;
10630
+ case "getChildMenus":
10631
+ await handleGetChildMenus(id, parentId, executeCollection, sendMessage, from.id);
10632
+ break;
10633
+ case "getHierarchy":
10634
+ await handleGetHierarchy(id, executeCollection, sendMessage, from.id);
10635
+ break;
10636
+ case "query":
10637
+ await handleQuery6(id, filters, limit, sort, executeCollection, sendMessage, from.id);
10638
+ break;
10639
+ case "reorder":
10640
+ await handleReorder(id, items, executeCollection, sendMessage, from.id);
10641
+ break;
10642
+ default:
10643
+ sendResponse9(id, {
10644
+ success: false,
10645
+ error: `Unknown operation: ${operation}`
10646
+ }, sendMessage, from.id);
10647
+ }
10648
+ } catch (error) {
10649
+ logger.error("Failed to handle menus request:", error);
10650
+ sendResponse9(null, {
10651
+ success: false,
10652
+ error: error instanceof Error ? error.message : "Unknown error occurred"
10653
+ }, sendMessage);
10654
+ }
10655
+ }
10656
+ async function handleCreate7(id, name, componentName, icon, userMessage, parentId, sortOrder, props, isActive, executeCollection, sendMessage, clientId) {
10657
+ if (!name) {
10658
+ sendResponse9(id, {
10659
+ success: false,
10660
+ error: "name is required"
10661
+ }, sendMessage, clientId);
10662
+ return;
10663
+ }
10664
+ if (!componentName) {
10665
+ sendResponse9(id, {
10666
+ success: false,
10667
+ error: "componentName is required"
10668
+ }, sendMessage, clientId);
10669
+ return;
10670
+ }
10671
+ try {
10672
+ const result = await executeCollection("menus", "create", {
10673
+ name,
10674
+ componentName,
10675
+ icon,
10676
+ userMessage,
10677
+ parentId,
10678
+ sortOrder,
10679
+ props,
10680
+ isActive
10681
+ });
10682
+ sendResponse9(id, {
10683
+ success: true,
10684
+ data: result.data,
10685
+ message: "Menu created successfully"
10686
+ }, sendMessage, clientId);
10687
+ logger.info(`Menu created: ID ${result.data?.id}`);
10688
+ } catch (error) {
10689
+ sendResponse9(id, {
10690
+ success: false,
10691
+ error: error instanceof Error ? error.message : "Failed to create menu"
10692
+ }, sendMessage, clientId);
10693
+ }
10694
+ }
10695
+ async function handleUpdate7(id, menuId, name, componentName, icon, userMessage, parentId, sortOrder, props, isActive, executeCollection, sendMessage, clientId) {
10696
+ if (!menuId) {
10697
+ sendResponse9(id, {
10698
+ success: false,
10699
+ error: "Menu ID is required"
10700
+ }, sendMessage, clientId);
10701
+ return;
10702
+ }
10703
+ try {
10704
+ const result = await executeCollection("menus", "update", {
10705
+ id: menuId,
10706
+ name,
10707
+ componentName,
10708
+ icon,
10709
+ userMessage,
10710
+ parentId,
10711
+ sortOrder,
10712
+ props,
10713
+ isActive
10714
+ });
10715
+ sendResponse9(id, {
10716
+ success: true,
10717
+ data: result.data,
10718
+ message: "Menu updated successfully"
10719
+ }, sendMessage, clientId);
10720
+ logger.info(`Menu updated: ID ${menuId}`);
10721
+ } catch (error) {
10722
+ sendResponse9(id, {
10723
+ success: false,
10724
+ error: error instanceof Error ? error.message : "Failed to update menu"
10725
+ }, sendMessage, clientId);
10726
+ }
10727
+ }
10728
+ async function handleDelete7(id, menuId, executeCollection, sendMessage, clientId) {
10729
+ if (!menuId) {
10730
+ sendResponse9(id, {
10731
+ success: false,
10732
+ error: "Menu ID is required"
10733
+ }, sendMessage, clientId);
10734
+ return;
10735
+ }
10736
+ try {
10737
+ const result = await executeCollection("menus", "delete", { id: menuId });
10738
+ sendResponse9(id, {
10739
+ success: true,
10740
+ data: result.data,
10741
+ message: "Menu deleted successfully"
10742
+ }, sendMessage, clientId);
10743
+ logger.info(`Menu deleted: ID ${menuId}`);
10744
+ } catch (error) {
10745
+ sendResponse9(id, {
10746
+ success: false,
10747
+ error: error instanceof Error ? error.message : "Failed to delete menu"
10748
+ }, sendMessage, clientId);
10749
+ }
10750
+ }
10751
+ async function handleGetAll7(id, executeCollection, sendMessage, clientId) {
10752
+ try {
10753
+ const result = await executeCollection("menus", "getAll", {});
10754
+ sendResponse9(id, {
10755
+ success: true,
10756
+ data: result.data,
10757
+ count: result.count,
10758
+ message: `Retrieved ${result.count} menus`
10759
+ }, sendMessage, clientId);
10760
+ logger.info(`Retrieved all menus (count: ${result.count})`);
10761
+ } catch (error) {
10762
+ sendResponse9(id, {
10763
+ success: false,
10764
+ error: error instanceof Error ? error.message : "Failed to get menus"
10765
+ }, sendMessage, clientId);
10766
+ }
10767
+ }
10768
+ async function handleGetOne7(id, menuId, executeCollection, sendMessage, clientId) {
10769
+ if (!menuId) {
10770
+ sendResponse9(id, {
10771
+ success: false,
10772
+ error: "Menu ID is required"
10773
+ }, sendMessage, clientId);
10774
+ return;
10775
+ }
10776
+ try {
10777
+ const result = await executeCollection("menus", "getOne", { id: menuId });
10778
+ sendResponse9(id, {
10779
+ success: true,
10780
+ data: result.data,
10781
+ message: `Retrieved menu ID ${menuId}`
10782
+ }, sendMessage, clientId);
10783
+ logger.info(`Retrieved menu: ID ${menuId}`);
10784
+ } catch (error) {
10785
+ sendResponse9(id, {
10786
+ success: false,
10787
+ error: error instanceof Error ? error.message : "Failed to get menu"
10788
+ }, sendMessage, clientId);
10789
+ }
10790
+ }
10791
+ async function handleGetRootMenus(id, executeCollection, sendMessage, clientId) {
10792
+ try {
10793
+ const result = await executeCollection("menus", "getRootMenus", {});
10794
+ sendResponse9(id, {
10795
+ success: true,
10796
+ data: result.data,
10797
+ count: result.count,
10798
+ message: `Retrieved ${result.count} root menus`
10799
+ }, sendMessage, clientId);
10800
+ logger.info(`Retrieved root menus (count: ${result.count})`);
10801
+ } catch (error) {
10802
+ sendResponse9(id, {
10803
+ success: false,
10804
+ error: error instanceof Error ? error.message : "Failed to get root menus"
10805
+ }, sendMessage, clientId);
10806
+ }
10807
+ }
10808
+ async function handleGetChildMenus(id, parentId, executeCollection, sendMessage, clientId) {
10809
+ if (parentId === void 0 || parentId === null) {
10810
+ sendResponse9(id, {
10811
+ success: false,
10812
+ error: "parentId is required"
10813
+ }, sendMessage, clientId);
10814
+ return;
10815
+ }
10816
+ try {
10817
+ const result = await executeCollection("menus", "getChildMenus", { parentId });
10818
+ sendResponse9(id, {
10819
+ success: true,
10820
+ data: result.data,
10821
+ count: result.count,
10822
+ message: `Retrieved ${result.count} child menus for parent ${parentId}`
10823
+ }, sendMessage, clientId);
10824
+ logger.info(`Retrieved child menus for parent ${parentId} (count: ${result.count})`);
10825
+ } catch (error) {
10826
+ sendResponse9(id, {
10827
+ success: false,
10828
+ error: error instanceof Error ? error.message : "Failed to get child menus"
10829
+ }, sendMessage, clientId);
10830
+ }
10831
+ }
10832
+ async function handleGetHierarchy(id, executeCollection, sendMessage, clientId) {
10833
+ try {
10834
+ const result = await executeCollection("menus", "getHierarchy", {});
10835
+ sendResponse9(id, {
10836
+ success: true,
10837
+ data: result.data,
10838
+ count: result.count,
10839
+ message: `Retrieved menus hierarchy with ${result.count} root items`
10840
+ }, sendMessage, clientId);
10841
+ logger.info(`Retrieved menus hierarchy (root count: ${result.count})`);
10842
+ } catch (error) {
10843
+ sendResponse9(id, {
10844
+ success: false,
10845
+ error: error instanceof Error ? error.message : "Failed to get menus hierarchy"
10846
+ }, sendMessage, clientId);
10847
+ }
10848
+ }
10849
+ async function handleQuery6(id, filters, limit, sort, executeCollection, sendMessage, clientId) {
10850
+ try {
10851
+ const result = await executeCollection("menus", "query", {
10852
+ filters: filters || {},
10853
+ limit,
10854
+ sort
10855
+ });
10856
+ sendResponse9(id, {
10857
+ success: true,
10858
+ data: result.data,
10859
+ count: result.count,
10860
+ message: `Query returned ${result.count} menus`
10861
+ }, sendMessage, clientId);
10862
+ logger.info(`Query returned ${result.count} menus`);
10863
+ } catch (error) {
10864
+ sendResponse9(id, {
10865
+ success: false,
10866
+ error: error instanceof Error ? error.message : "Failed to query menus"
10867
+ }, sendMessage, clientId);
10868
+ }
10869
+ }
10870
+ async function handleReorder(id, items, executeCollection, sendMessage, clientId) {
10871
+ if (!items || !Array.isArray(items) || items.length === 0) {
10872
+ sendResponse9(id, {
10873
+ success: false,
10874
+ error: "items array is required"
10875
+ }, sendMessage, clientId);
10876
+ return;
10877
+ }
10878
+ try {
10879
+ const result = await executeCollection("menus", "reorder", { items });
10880
+ sendResponse9(id, {
10881
+ success: true,
10882
+ data: result.data,
10883
+ message: `Reordered ${items.length} menus successfully`
10884
+ }, sendMessage, clientId);
10885
+ logger.info(`Reordered ${items.length} menus`);
10886
+ } catch (error) {
10887
+ sendResponse9(id, {
10888
+ success: false,
10889
+ error: error instanceof Error ? error.message : "Failed to reorder menus"
10890
+ }, sendMessage, clientId);
10891
+ }
10892
+ }
10893
+ function sendResponse9(id, res, sendMessage, clientId) {
10894
+ const response = {
10895
+ id: id || "unknown",
10896
+ type: "MENUS_RES",
10897
+ from: { type: "data-agent" },
10898
+ to: {
10899
+ type: "admin",
10900
+ id: clientId
10901
+ },
10902
+ payload: {
10903
+ ...res
10904
+ }
10905
+ };
10906
+ sendMessage(response);
10907
+ }
10908
+
10377
10909
  // src/dashComp/index.ts
10378
10910
  init_logger();
10379
10911
 
@@ -10500,37 +11032,74 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10500
11032
  return { success: false, errors };
10501
11033
  }
10502
11034
  logger.info(`[DASH_COMP_REQ] Using model: ${model}`);
10503
- const result = await LLM.stream(
11035
+ const executedTools = [];
11036
+ const llmTools = (tools || []).map((tool) => ({
11037
+ name: tool.id,
11038
+ description: tool.description,
11039
+ input_schema: {
11040
+ type: "object",
11041
+ properties: Object.fromEntries(
11042
+ 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` }])
11043
+ ),
11044
+ additionalProperties: false
11045
+ }
11046
+ }));
11047
+ const toolHandler = async (toolName, toolInput) => {
11048
+ const tool = tools?.find((t) => t.id === toolName);
11049
+ if (!tool) {
11050
+ throw new Error(`Unknown tool: ${toolName}`);
11051
+ }
11052
+ logger.info(`[DASH_COMP_REQ] Executing external tool: ${tool.name} (${tool.id})`);
11053
+ const result2 = await tool.fn(toolInput);
11054
+ executedTools.push({
11055
+ id: tool.id,
11056
+ name: tool.name,
11057
+ params: toolInput,
11058
+ result: result2,
11059
+ outputSchema: tool.outputSchema
11060
+ });
11061
+ logger.info(`[DASH_COMP_REQ] Tool ${tool.name} executed successfully`);
11062
+ return JSON.stringify(result2, null, 2);
11063
+ };
11064
+ const result = await LLM.streamWithTools(
10504
11065
  {
10505
11066
  sys: prompts.system,
10506
11067
  user: prompts.user
10507
11068
  },
11069
+ llmTools,
11070
+ toolHandler,
10508
11071
  {
10509
11072
  model,
10510
11073
  maxTokens: 8192,
10511
11074
  temperature: 0.2,
10512
11075
  apiKey
10513
11076
  },
10514
- true
10515
- // Parse as JSON
11077
+ 5
11078
+ // max iterations
10516
11079
  );
11080
+ const jsonMatch = result.match(/\{[\s\S]*\}/);
11081
+ const parsedResult = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
11082
+ if (!parsedResult) {
11083
+ errors.push("Failed to parse LLM response as JSON");
11084
+ return { success: false, errors };
11085
+ }
10517
11086
  logger.debug("[DASH_COMP_REQ] LLM response received");
10518
- logger.file("[DASH_COMP_REQ] LLM response:", JSON.stringify(result, null, 2));
10519
- if (!result.componentId || !result.props) {
11087
+ logger.file("[DASH_COMP_REQ] LLM response:", JSON.stringify(parsedResult, null, 2));
11088
+ if (!parsedResult.componentId || !parsedResult.props) {
10520
11089
  errors.push("Invalid LLM response: missing componentId or props");
10521
11090
  userPromptErrorLogger.logError("DASH_COMP_REQ", "Invalid LLM response structure", {
10522
11091
  prompt,
10523
- result,
10524
- missingFields: { componentId: !result.componentId, props: !result.props }
11092
+ result: parsedResult,
11093
+ missingFields: { componentId: !parsedResult.componentId, props: !parsedResult.props }
10525
11094
  });
10526
11095
  return { success: false, errors };
10527
11096
  }
10528
- const originalComponent = components.find((c) => c.name === result.componentName);
11097
+ const originalComponent = components.find((c) => c.name === parsedResult.componentName);
10529
11098
  if (!originalComponent) {
10530
- errors.push(`Component ${result.componentName} not found in available components`);
11099
+ errors.push(`Component ${parsedResult.componentName} not found in available components`);
10531
11100
  userPromptErrorLogger.logError("DASH_COMP_REQ", "Component not found", {
10532
11101
  prompt,
10533
- componentName: result.componentName,
11102
+ componentName: parsedResult.componentName,
10534
11103
  availableComponentNames: components.map((c) => c.name)
10535
11104
  });
10536
11105
  return { success: false, errors };
@@ -10539,23 +11108,27 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10539
11108
  ...originalComponent,
10540
11109
  props: {
10541
11110
  ...originalComponent.props,
10542
- ...result.props
11111
+ ...parsedResult.props
10543
11112
  }
10544
11113
  };
10545
11114
  logger.info(`[DASH_COMP_REQ] Successfully picked component: ${finalComponent.name} (${finalComponent.type})`);
10546
- if (result.props.query) {
11115
+ if (parsedResult.props.query) {
10547
11116
  logger.info(`[DASH_COMP_REQ] Data source: Database query`);
10548
11117
  }
10549
- if (result.props.externalTool) {
10550
- logger.info(`[DASH_COMP_REQ] Data source: External tool - ${result.props.externalTool.toolName}`);
11118
+ if (parsedResult.props.externalTool) {
11119
+ logger.info(`[DASH_COMP_REQ] Data source: External tool - ${parsedResult.props.externalTool.toolName}`);
11120
+ }
11121
+ if (executedTools.length > 0) {
11122
+ logger.info(`[DASH_COMP_REQ] Executed ${executedTools.length} external tool(s): ${executedTools.map((t) => t.name).join(", ")}`);
10551
11123
  }
10552
11124
  return {
10553
11125
  success: true,
10554
11126
  data: {
10555
11127
  component: finalComponent,
10556
- reasoning: result.reasoning || "Component selected based on user prompt",
10557
- dataSource: result.props.query ? "database" : result.props.externalTool ? "external_tool" : "none",
10558
- isUpdate: result.isUpdate || false
11128
+ reasoning: parsedResult.reasoning || "Component selected based on user prompt",
11129
+ dataSource: parsedResult.props.query ? "database" : parsedResult.props.externalTool ? "external_tool" : "none",
11130
+ isUpdate: parsedResult.isUpdate || false,
11131
+ executedTools: executedTools.length > 0 ? executedTools : void 0
10559
11132
  },
10560
11133
  errors: []
10561
11134
  };
@@ -10608,11 +11181,49 @@ async function createFilterWithLLM(prompt, components, existingComponents, anthr
10608
11181
  return { success: false, errors };
10609
11182
  }
10610
11183
  logger.info(`[DASH_COMP_REQ:FILTER] Using model: ${model}`);
10611
- const result = await LLM.stream(
11184
+ const executedTools = [];
11185
+ const llmTools = (tools || []).map((tool) => ({
11186
+ name: tool.id,
11187
+ description: tool.description,
11188
+ input_schema: {
11189
+ type: "object",
11190
+ properties: Object.fromEntries(
11191
+ 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` }])
11192
+ ),
11193
+ additionalProperties: false
11194
+ }
11195
+ }));
11196
+ const toolHandler = async (toolName, toolInput) => {
11197
+ const tool = tools?.find((t) => t.id === toolName);
11198
+ if (!tool) {
11199
+ throw new Error(`Unknown tool: ${toolName}`);
11200
+ }
11201
+ logger.info(`[DASH_COMP_REQ:FILTER] Executing external tool: ${tool.name} (${tool.id})`);
11202
+ const result2 = await tool.fn(toolInput);
11203
+ executedTools.push({
11204
+ id: tool.id,
11205
+ name: tool.name,
11206
+ params: toolInput,
11207
+ result: result2,
11208
+ outputSchema: tool.outputSchema
11209
+ });
11210
+ logger.info(`[DASH_COMP_REQ:FILTER] Tool ${tool.name} executed successfully`);
11211
+ return JSON.stringify(result2, null, 2);
11212
+ };
11213
+ const rawResult = await LLM.streamWithTools(
10612
11214
  { sys: prompts.system, user: prompts.user },
11215
+ llmTools,
11216
+ toolHandler,
10613
11217
  { model, maxTokens: 16384, temperature: 0.2, apiKey },
10614
- true
11218
+ 5
11219
+ // max iterations
10615
11220
  );
11221
+ const jsonMatch = rawResult.match(/\{[\s\S]*\}/);
11222
+ const result = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
11223
+ if (!result) {
11224
+ errors.push("Failed to parse LLM response as JSON");
11225
+ return { success: false, errors };
11226
+ }
10616
11227
  logger.debug("[DASH_COMP_REQ:FILTER] LLM response received");
10617
11228
  logger.file("[DASH_COMP_REQ:FILTER] LLM response:", JSON.stringify(result, null, 2));
10618
11229
  if (!result.filterComponent) {
@@ -10626,13 +11237,17 @@ async function createFilterWithLLM(prompt, components, existingComponents, anthr
10626
11237
  }
10627
11238
  logger.info(`[DASH_COMP_REQ:FILTER] Successfully created filter: ${result.filterComponent.componentType}`);
10628
11239
  logger.info(`[DASH_COMP_REQ:FILTER] Updated ${result.updatedComponents?.length || 0} components`);
11240
+ if (executedTools.length > 0) {
11241
+ logger.info(`[DASH_COMP_REQ:FILTER] Executed ${executedTools.length} external tool(s): ${executedTools.map((t) => t.name).join(", ")}`);
11242
+ }
10629
11243
  return {
10630
11244
  success: true,
10631
11245
  data: {
10632
11246
  filterComponent: result.filterComponent,
10633
11247
  updatedComponents: result.updatedComponents || [],
10634
11248
  filterBindings: result.filterBindings || {},
10635
- reasoning: result.reasoning || "Filter created based on user prompt"
11249
+ reasoning: result.reasoning || "Filter created based on user prompt",
11250
+ executedTools: executedTools.length > 0 ? executedTools : void 0
10636
11251
  },
10637
11252
  errors: []
10638
11253
  };
@@ -11810,6 +12425,11 @@ var SuperatomSDK = class {
11810
12425
  logger.error("Failed to handle KB nodes request:", error);
11811
12426
  });
11812
12427
  break;
12428
+ case "MENUS":
12429
+ handleMenusRequest(parsed, this.collections, (msg) => this.send(msg)).catch((error) => {
12430
+ logger.error("Failed to handle menus request:", error);
12431
+ });
12432
+ break;
11813
12433
  case "DASH_COMP_REQ":
11814
12434
  handleDashCompRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.geminiApiKey, this.openaiApiKey, this.llmProviders, this.collections, this.tools).catch((error) => {
11815
12435
  logger.error("Failed to handle dash comp request:", error);