@superatomai/sdk-node 0.0.52 → 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,35 +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"}`;
5678
5800
  const fieldsText = fields.map(
5679
- (f) => ` - name: "${f.name}" \u2190 USE THIS EXACT VALUE in config
5680
- type: ${f.type}
5681
- description: ${f.description}`
5801
+ (f) => ` "${f.name}" (${f.type}): ${f.description}`
5682
5802
  ).join("\n");
5683
5803
  outputSchemaText = `${tool.outputSchema.description}
5684
- Fields (use the "name" value in your config):
5804
+ Fields:
5685
5805
  ${fieldsText}`;
5686
5806
  }
5687
5807
  return `${idx + 1}. **${tool.name}**
5688
- toolId: "${tool.id}" (USE THIS EXACT VALUE for externalTool.toolId)
5689
- toolName: "${tool.name}" (USE THIS EXACT VALUE for externalTool.toolName)
5690
- parameters: ${JSON.stringify(tool.params || {})} (USE THESE for externalTool.parameters)
5808
+ toolId: "${tool.id}"
5809
+ toolName: "${tool.name}"
5810
+ parameters: ${JSON.stringify(tool.params || {})}
5691
5811
  recordCount: ${recordCount} rows returned
5692
- outputSchema: ${outputSchemaText}
5693
- \u26A0\uFE0F DO NOT embed this tool's data in SQL - use externalTool prop OR query database tables`;
5812
+ outputSchema: ${outputSchemaText}${fieldNamesList}`;
5694
5813
  }).join("\n\n");
5695
5814
  }
5696
5815
  const schemaDoc = schema.generateSchemaDocumentation();
5697
5816
  const databaseRules = await promptLoader.loadDatabaseRules();
5698
- logger.file("\n=============================\nText analysis response:", analysisContent);
5699
- logger.file("\n=============================\nDeferred tools:", deferredToolsText);
5700
- logger.file("\n=============================\nExecuted tools:", executedToolsText);
5701
5817
  const prompts = await promptLoader.loadPrompts("match-text-components", {
5702
5818
  ANALYSIS_CONTENT: analysisContent,
5703
5819
  AVAILABLE_COMPONENTS: availableComponentsText,
@@ -5707,7 +5823,13 @@ ${fieldsText}`;
5707
5823
  EXECUTED_TOOLS: executedToolsText
5708
5824
  });
5709
5825
  logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
5710
- 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}`);
5711
5833
  logCollector?.info("Matching components from text response...");
5712
5834
  let fullResponseText = "";
5713
5835
  let answerComponentExtracted = false;
@@ -5844,40 +5966,41 @@ ${fieldsText}`;
5844
5966
  if (executedTool?.outputSchema?.fields && cleanedProps.config) {
5845
5967
  const validFieldNames = executedTool.outputSchema.fields.map((f) => f.name);
5846
5968
  const validFieldNamesLower = validFieldNames.map((n) => n.toLowerCase());
5847
- const findMatchingField = (fieldName) => {
5969
+ const findMatchingField = (fieldName, configKey) => {
5848
5970
  if (!fieldName) return null;
5849
5971
  const lowerField = fieldName.toLowerCase();
5850
5972
  const exactIdx = validFieldNamesLower.indexOf(lowerField);
5851
5973
  if (exactIdx !== -1) return validFieldNames[exactIdx];
5852
- const partialMatches = [];
5853
- for (let i = 0; i < validFieldNames.length; i++) {
5854
- const validName = validFieldNames[i];
5855
- const validLower = validFieldNamesLower[i];
5856
- if (validLower.endsWith(lowerField)) {
5857
- const score = lowerField.length / validLower.length;
5858
- partialMatches.push({ name: validName, score });
5859
- continue;
5860
- }
5861
- if (lowerField.endsWith(validLower)) {
5862
- const score = validLower.length / lowerField.length;
5863
- partialMatches.push({ name: validName, score });
5864
- continue;
5865
- }
5866
- if (validLower.endsWith(lowerField) || lowerField.length <= 5 && validLower.includes(lowerField)) {
5867
- const score = lowerField.length <= 5 ? 0.3 : 0.5;
5868
- partialMatches.push({ name: validName, score });
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];
5869
5991
  }
5870
5992
  }
5871
- if (partialMatches.length > 0) {
5872
- partialMatches.sort((a, b) => b.score - a.score);
5873
- if (partialMatches.length === 1 || partialMatches[0].score > partialMatches[1].score + 0.1) {
5874
- return partialMatches[0].name;
5875
- } else {
5876
- logger.warn(`[${this.getProviderName()}] Ambiguous field match for "${fieldName}": ${partialMatches.map((m) => m.name).join(", ")}`);
5877
- return null;
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];
5878
6000
  }
5879
6001
  }
5880
- return null;
6002
+ logger.warn(`[${this.getProviderName()}] No match for "${fieldName}", using first field: ${validFieldNames[0]}`);
6003
+ return validFieldNames[0];
5881
6004
  };
5882
6005
  const configFieldsToValidate = [
5883
6006
  "xAxisKey",
@@ -5896,12 +6019,10 @@ ${fieldsText}`;
5896
6019
  const fieldValue = cleanedProps.config[configKey];
5897
6020
  if (fieldValue && typeof fieldValue === "string") {
5898
6021
  if (!validFieldNames.includes(fieldValue)) {
5899
- const correctedField = findMatchingField(fieldValue);
6022
+ const correctedField = findMatchingField(fieldValue, configKey);
5900
6023
  if (correctedField) {
5901
6024
  logger.warn(`[${this.getProviderName()}] Correcting config.${configKey}: "${fieldValue}" \u2192 "${correctedField}"`);
5902
6025
  cleanedProps.config[configKey] = correctedField;
5903
- } else {
5904
- logger.warn(`[${this.getProviderName()}] config.${configKey}="${fieldValue}" not found in outputSchema [${validFieldNames.join(", ")}]`);
5905
6026
  }
5906
6027
  }
5907
6028
  }
@@ -5909,7 +6030,7 @@ ${fieldsText}`;
5909
6030
  if (Array.isArray(cleanedProps.config.series)) {
5910
6031
  cleanedProps.config.series = cleanedProps.config.series.map((s) => {
5911
6032
  if (s.dataKey && typeof s.dataKey === "string" && !validFieldNames.includes(s.dataKey)) {
5912
- const correctedField = findMatchingField(s.dataKey);
6033
+ const correctedField = findMatchingField(s.dataKey, "yAxisKey");
5913
6034
  if (correctedField) {
5914
6035
  logger.warn(`[${this.getProviderName()}] Correcting series.dataKey: "${s.dataKey}" \u2192 "${correctedField}"`);
5915
6036
  return { ...s, dataKey: correctedField };
@@ -5976,6 +6097,10 @@ ${fieldsText}`;
5976
6097
  AVAILABLE_TOOLS: availableToolsDoc,
5977
6098
  SCHEMA_DOC: schemaDoc || "No database schema available"
5978
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);
5979
6104
  const result = await LLM.stream(
5980
6105
  {
5981
6106
  sys: prompts.system,
@@ -6163,7 +6288,6 @@ ${fieldsText}`;
6163
6288
  collections,
6164
6289
  topK: 1
6165
6290
  });
6166
- logger.file("\n=============================\nknowledge base context:", knowledgeBaseContext);
6167
6291
  const prompts = await promptLoader.loadPrompts("text-response", {
6168
6292
  USER_PROMPT: userPrompt,
6169
6293
  CONVERSATION_HISTORY: conversationHistory || "No previous conversation",
@@ -6172,8 +6296,10 @@ ${fieldsText}`;
6172
6296
  KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext || "No additional knowledge base context available.",
6173
6297
  AVAILABLE_EXTERNAL_TOOLS: availableToolsDoc
6174
6298
  });
6175
- logger.file("\n=============================\nsystem prompt:", prompts.system);
6176
- 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);
6177
6303
  logger.debug(`[${this.getProviderName()}] Loaded text-response prompts with schema`);
6178
6304
  logger.debug(`[${this.getProviderName()}] System prompt length: ${prompts.system.length}, User prompt length: ${prompts.user.length}`);
6179
6305
  logCollector?.info("Generating text response with query execution capability...");
@@ -6559,7 +6685,6 @@ ${errorMsg}
6559
6685
  data: {
6560
6686
  text: textResponse,
6561
6687
  // Include the streamed text showing all attempts
6562
- matchedComponents: [],
6563
6688
  actions: [],
6564
6689
  method: `${this.getProviderName()}-text-response-max-attempts`
6565
6690
  }
@@ -6657,7 +6782,6 @@ ${errorMsg}
6657
6782
  success: true,
6658
6783
  data: {
6659
6784
  text: textResponse,
6660
- matchedComponents,
6661
6785
  component: container_componet,
6662
6786
  actions,
6663
6787
  method: `${this.getProviderName()}-text-response`
@@ -6681,7 +6805,6 @@ ${errorMsg}
6681
6805
  errors,
6682
6806
  data: {
6683
6807
  text: "I apologize, but I encountered an error while processing your question. Please try rephrasing or ask something else.",
6684
- matchedComponents: [],
6685
6808
  actions: [],
6686
6809
  method: `${this.getProviderName()}-text-response-error`
6687
6810
  }
@@ -6705,6 +6828,8 @@ ${errorMsg}
6705
6828
  const startTime = Date.now();
6706
6829
  logger.info(`[${this.getProviderName()}] handleUserRequest called for user prompt: ${userPrompt}`);
6707
6830
  logCollector?.info(`Starting request processing with mode: ${responseMode}`);
6831
+ logger.clearFile();
6832
+ logger.logLLMPrompt("handleUserRequest", "user", `User Prompt: ${userPrompt}`);
6708
6833
  try {
6709
6834
  logger.info(`[${this.getProviderName()}] Step 1: Searching previous conversations...`);
6710
6835
  logCollector?.info("Step 1: Searching for similar previous conversations...");
@@ -6712,8 +6837,8 @@ ${errorMsg}
6712
6837
  userPrompt,
6713
6838
  collections,
6714
6839
  userId,
6715
- similarityThreshold: 0.75
6716
- // 75% threshold
6840
+ similarityThreshold: 0.8
6841
+ // 80% threshold
6717
6842
  });
6718
6843
  if (conversationMatch) {
6719
6844
  logger.info(`[${this.getProviderName()}] \u2713 Found matching conversation with ${(conversationMatch.similarity * 100).toFixed(2)}% similarity`);
@@ -6738,7 +6863,6 @@ ${errorMsg}
6738
6863
  data: {
6739
6864
  text: cachedTextResponse,
6740
6865
  component: null,
6741
- matchedComponents: [],
6742
6866
  actions: conversationMatch.uiBlock?.actions || [],
6743
6867
  reasoning: `Exact match from previous general conversation`,
6744
6868
  method: `${this.getProviderName()}-semantic-match-general`,
@@ -6766,7 +6890,6 @@ ${errorMsg}
6766
6890
  data: {
6767
6891
  text: cachedTextResponse,
6768
6892
  component,
6769
- matchedComponents: component?.props?.config?.components || [],
6770
6893
  actions: cachedActions,
6771
6894
  reasoning: `Exact match from previous conversation (${(conversationMatch.similarity * 100).toFixed(2)}% similarity)`,
6772
6895
  method: `${this.getProviderName()}-semantic-match-exact`,
@@ -6802,7 +6925,6 @@ ${errorMsg}
6802
6925
  data: {
6803
6926
  text: textResponseToUse,
6804
6927
  component: adaptResult.adaptedComponent,
6805
- matchedComponents: adaptResult.adaptedComponent?.props?.config?.components || [],
6806
6928
  actions: cachedActions,
6807
6929
  reasoning: `Adapted from previous conversation: ${originalPrompt}`,
6808
6930
  method: `${this.getProviderName()}-semantic-match`,
@@ -10409,6 +10531,331 @@ function sendResponse8(id, res, sendMessage, clientId) {
10409
10531
  sendMessage(response);
10410
10532
  }
10411
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
+
10412
10859
  // src/dashComp/index.ts
10413
10860
  init_logger();
10414
10861
 
@@ -10535,37 +10982,74 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10535
10982
  return { success: false, errors };
10536
10983
  }
10537
10984
  logger.info(`[DASH_COMP_REQ] Using model: ${model}`);
10538
- 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(
10539
11015
  {
10540
11016
  sys: prompts.system,
10541
11017
  user: prompts.user
10542
11018
  },
11019
+ llmTools,
11020
+ toolHandler,
10543
11021
  {
10544
11022
  model,
10545
11023
  maxTokens: 8192,
10546
11024
  temperature: 0.2,
10547
11025
  apiKey
10548
11026
  },
10549
- true
10550
- // Parse as JSON
11027
+ 5
11028
+ // max iterations
10551
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
+ }
10552
11036
  logger.debug("[DASH_COMP_REQ] LLM response received");
10553
- logger.file("[DASH_COMP_REQ] LLM response:", JSON.stringify(result, null, 2));
10554
- if (!result.componentId || !result.props) {
11037
+ logger.file("[DASH_COMP_REQ] LLM response:", JSON.stringify(parsedResult, null, 2));
11038
+ if (!parsedResult.componentId || !parsedResult.props) {
10555
11039
  errors.push("Invalid LLM response: missing componentId or props");
10556
11040
  userPromptErrorLogger.logError("DASH_COMP_REQ", "Invalid LLM response structure", {
10557
11041
  prompt,
10558
- result,
10559
- missingFields: { componentId: !result.componentId, props: !result.props }
11042
+ result: parsedResult,
11043
+ missingFields: { componentId: !parsedResult.componentId, props: !parsedResult.props }
10560
11044
  });
10561
11045
  return { success: false, errors };
10562
11046
  }
10563
- const originalComponent = components.find((c) => c.name === result.componentName);
11047
+ const originalComponent = components.find((c) => c.name === parsedResult.componentName);
10564
11048
  if (!originalComponent) {
10565
- errors.push(`Component ${result.componentName} not found in available components`);
11049
+ errors.push(`Component ${parsedResult.componentName} not found in available components`);
10566
11050
  userPromptErrorLogger.logError("DASH_COMP_REQ", "Component not found", {
10567
11051
  prompt,
10568
- componentName: result.componentName,
11052
+ componentName: parsedResult.componentName,
10569
11053
  availableComponentNames: components.map((c) => c.name)
10570
11054
  });
10571
11055
  return { success: false, errors };
@@ -10574,23 +11058,27 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10574
11058
  ...originalComponent,
10575
11059
  props: {
10576
11060
  ...originalComponent.props,
10577
- ...result.props
11061
+ ...parsedResult.props
10578
11062
  }
10579
11063
  };
10580
11064
  logger.info(`[DASH_COMP_REQ] Successfully picked component: ${finalComponent.name} (${finalComponent.type})`);
10581
- if (result.props.query) {
11065
+ if (parsedResult.props.query) {
10582
11066
  logger.info(`[DASH_COMP_REQ] Data source: Database query`);
10583
11067
  }
10584
- if (result.props.externalTool) {
10585
- 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(", ")}`);
10586
11073
  }
10587
11074
  return {
10588
11075
  success: true,
10589
11076
  data: {
10590
11077
  component: finalComponent,
10591
- reasoning: result.reasoning || "Component selected based on user prompt",
10592
- dataSource: result.props.query ? "database" : result.props.externalTool ? "external_tool" : "none",
10593
- 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
10594
11082
  },
10595
11083
  errors: []
10596
11084
  };
@@ -10643,11 +11131,49 @@ async function createFilterWithLLM(prompt, components, existingComponents, anthr
10643
11131
  return { success: false, errors };
10644
11132
  }
10645
11133
  logger.info(`[DASH_COMP_REQ:FILTER] Using model: ${model}`);
10646
- 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(
10647
11164
  { sys: prompts.system, user: prompts.user },
11165
+ llmTools,
11166
+ toolHandler,
10648
11167
  { model, maxTokens: 16384, temperature: 0.2, apiKey },
10649
- true
11168
+ 5
11169
+ // max iterations
10650
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
+ }
10651
11177
  logger.debug("[DASH_COMP_REQ:FILTER] LLM response received");
10652
11178
  logger.file("[DASH_COMP_REQ:FILTER] LLM response:", JSON.stringify(result, null, 2));
10653
11179
  if (!result.filterComponent) {
@@ -10661,13 +11187,17 @@ async function createFilterWithLLM(prompt, components, existingComponents, anthr
10661
11187
  }
10662
11188
  logger.info(`[DASH_COMP_REQ:FILTER] Successfully created filter: ${result.filterComponent.componentType}`);
10663
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
+ }
10664
11193
  return {
10665
11194
  success: true,
10666
11195
  data: {
10667
11196
  filterComponent: result.filterComponent,
10668
11197
  updatedComponents: result.updatedComponents || [],
10669
11198
  filterBindings: result.filterBindings || {},
10670
- 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
10671
11201
  },
10672
11202
  errors: []
10673
11203
  };
@@ -11845,6 +12375,11 @@ var SuperatomSDK = class {
11845
12375
  logger.error("Failed to handle KB nodes request:", error);
11846
12376
  });
11847
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;
11848
12383
  case "DASH_COMP_REQ":
11849
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) => {
11850
12385
  logger.error("Failed to handle dash comp request:", error);