@superatomai/sdk-node 0.0.41 → 0.0.43

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
@@ -1028,11 +1028,29 @@ Analyze the user's request and:
1028
1028
  2. **Match by Type**: Choose the component type that best fits the data visualization or action need
1029
1029
  3. **Match by Description**: Use component descriptions and keywords to find the best fit
1030
1030
 
1031
+ ## Component Update Handling
1032
+
1033
+ The user prompt may contain an **existing component** to update. Detect this by looking for:
1034
+ - JSON object with \`componentId\`, \`props\`, or similar component structure in the prompt
1035
+ - Phrases like "update this", "modify", "change", "edit this component"
1036
+
1037
+ ### When UPDATING an existing component:
1038
+ 1. **Preserve the \`componentId\`** from the current component (do NOT pick a new one)
1039
+ 2. **Keep the same \`componentType\`** unless the user explicitly asks to change it
1040
+ 3. **Merge props**: Start with existing props, then modify only what the user requested
1041
+ 4. **Set \`isUpdate: true\`** in your response
1042
+ 5. **Preserve unmentioned props**: If user only asks to change the query, keep title/config unchanged
1043
+
1044
+ ### When CREATING a new component:
1045
+ 1. Pick the best component from the available list
1046
+ 2. Generate all props from scratch
1047
+ 3. Set \`isUpdate: false\` in your response
1048
+
1031
1049
  ## Data Source Decision
1032
1050
 
1033
1051
  ### Use DATABASE when:
1034
- - User asks about data that exists in the database schema (customers, orders, products, etc.)
1035
- - Questions about internal business data (sales, inventory, users, transactions)
1052
+ - User asks about data that exists in the database schema
1053
+ - Questions about internal business data
1036
1054
  - CRUD operations on database tables
1037
1055
 
1038
1056
  ### Use EXTERNAL TOOL when:
@@ -1113,11 +1131,12 @@ Analyze the user's request and:
1113
1131
  You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1114
1132
 
1115
1133
  {
1116
- "componentId": "id_from_available_list",
1134
+ "componentId": "id_from_available_list_or_existing_component_id",
1117
1135
  "componentName": "name_of_component",
1118
1136
  "componentType": "type_of_component",
1119
1137
  "dataSourceType": "database" | "external_tool",
1120
1138
  "operationType": "view" | "create" | "update" | "delete",
1139
+ "isUpdate": true | false,
1121
1140
  "reasoning": "Why this component was selected and why this data source",
1122
1141
  "props": {
1123
1142
  // Generate ALL props based on the component's Props Structure
@@ -1128,25 +1147,165 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1128
1147
 
1129
1148
  **CRITICAL:**
1130
1149
  - Return ONLY valid JSON (no markdown code blocks, no text before/after)
1131
- - \`componentId\` MUST match an ID from the available components list
1150
+ - \`componentId\`: For new components, MUST match an ID from the available components list. For updates, preserve the existing component's ID
1151
+ - \`isUpdate\`: Set to \`true\` if updating an existing component, \`false\` if creating new
1132
1152
  - \`dataSourceType\` indicates whether data comes from database or external tool
1133
- - \`operationType\` indicates the type of operation (view/create/update/delete)
1153
+ - \`operationType\` indicates the type of data operation (view/create/update/delete)
1134
1154
  - Generate COMPLETE props based on the component's "Props Structure"
1135
1155
  - For queries, ALWAYS use \`$paramName\` placeholders and include \`params\` object
1136
1156
  - For external tools, \`toolId\` MUST match an ID from the available tools list
1137
1157
 
1158
+ ## Database Schema
1159
+ {{SCHEMA_DOC}}
1160
+
1161
+ ## Available External Tools
1162
+ {{AVAILABLE_TOOLS}}
1163
+
1164
+ ## Available Components
1165
+ {{AVAILABLE_COMPONENTS}}
1166
+
1138
1167
  ---
1139
1168
 
1140
- ## CONTEXT (for this specific request)
1169
+ ## CONTEXT`,
1170
+ user: `{{USER_PROMPT}}`
1171
+ },
1172
+ "dash-filter-picker": {
1173
+ system: `You are a dashboard filter expert that creates filter components and updates existing dashboard components to work with the filter.
1174
+
1175
+ ## Your Task
1176
+
1177
+ 1. **Create a filter component** based on the user's request (DatePicker, Dropdown, SearchBox, etc.)
1178
+ 2. **Update all existing components** to use the filter values in their queries/params
1179
+
1180
+ ## Filter Types
1181
+
1182
+ Choose the appropriate filter component based on user intent:
1183
+ - **DateRangePicker**: For date range filtering (start date, end date)
1184
+ - **DatePicker**: For single date filtering
1185
+ - **Dropdown**: For categorical filtering (status, category, type, etc.)
1186
+ - **MultiSelect**: For multiple value selection
1187
+ - **SearchBox**: For text search filtering
1188
+ - **NumberRange**: For numeric range filtering
1189
+
1190
+ ## Filter Component Structure
1191
+
1192
+ Generate a filter component with these props:
1193
+ \`\`\`json
1194
+ {
1195
+ "componentId": "unique_filter_id",
1196
+ "componentType": "DateRangePicker | Dropdown | SearchBox | etc.",
1197
+ "componentName": "Display Name",
1198
+ "props": {
1199
+ "filterId": "unique_filter_id",
1200
+ "label": "Filter Label",
1201
+ "defaultValue": "optional default value",
1202
+ "options": []
1203
+ }
1204
+ }
1205
+ \`\`\`
1206
+
1207
+ ## Updating Existing Components
1208
+
1209
+ For each existing component, update its query/externalTool to use the filter:
1210
+
1211
+ ### For Database Queries:
1212
+ - Add filter conditions to WHERE clause using \`$paramName\` placeholders
1213
+ - Add the filter param to the \`params\` object with binding reference
1214
+
1215
+ ### For External Tools:
1216
+ - Add filter params to the tool's params object with binding reference
1217
+
1218
+ ## Filter Bindings
1141
1219
 
1142
- ### Database Schema
1220
+ Use this binding format to connect filter values to component params:
1221
+ \`\`\`json
1222
+ {
1223
+ "paramName": "$filter.filterId.value"
1224
+ }
1225
+ \`\`\`
1226
+
1227
+ For DateRangePicker:
1228
+ - \`$filter.filterId.startDate\`
1229
+ - \`$filter.filterId.endDate\`
1230
+
1231
+ For Dropdown/MultiSelect:
1232
+ - \`$filter.filterId.value\`
1233
+
1234
+ For SearchBox:
1235
+ - \`$filter.filterId.searchText\`
1236
+
1237
+ ### Database Query Rules
1238
+ {{DATABASE_RULES}}
1239
+
1240
+ ## Output Format
1241
+
1242
+ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1243
+
1244
+ {
1245
+ "filterComponent": {
1246
+ "componentId": "filter_unique_id",
1247
+ "componentType": "DateRangePicker | Dropdown | etc.",
1248
+ "componentName": "Filter Display Name",
1249
+ "props": {
1250
+ "filterId": "filter_unique_id",
1251
+ "label": "Filter Label",
1252
+ "defaultValue": null,
1253
+ "options": []
1254
+ }
1255
+ },
1256
+ "updatedComponents": [
1257
+ {
1258
+ "componentId": "existing_component_id",
1259
+ "componentType": "existing_type",
1260
+ "componentName": "existing_name",
1261
+ "props": {
1262
+ // RETURN THE COMPLETE PROPS OBJECT
1263
+ // Copy ALL existing props and only modify the necessary fields
1264
+ "title": "Existing Title",
1265
+ "description": "Existing Description",
1266
+ "config": {},
1267
+ "query": {
1268
+ "sql": "SELECT ... WHERE column BETWEEN $startDate AND $endDate",
1269
+ "params": {
1270
+ "existingParam": "existing_value",
1271
+ "startDate": "$filter.filterId.startDate",
1272
+ "endDate": "$filter.filterId.endDate"
1273
+ }
1274
+ }
1275
+ }
1276
+ }
1277
+ ],
1278
+ "filterBindings": {
1279
+ "startDate": "$filter.filterId.startDate",
1280
+ "endDate": "$filter.filterId.endDate"
1281
+ },
1282
+ "reasoning": "Explanation of filter choice and how components were updated"
1283
+ }
1284
+
1285
+ **CRITICAL:**
1286
+ - Return ONLY valid JSON (no markdown code blocks, no text before/after)
1287
+ - **RETURN COMPLETE PROPS**: Copy ALL existing props from each component, only modify what's needed for the filter
1288
+ - Do NOT omit existing props like title, description, config - include them unchanged
1289
+ - Only modify query.sql (add WHERE conditions) and query.params (add filter bindings)
1290
+ - For externalTool, only add filter params to the params object
1291
+ - Use consistent param naming across all components
1292
+ - Ensure SQL syntax is valid with the new filter conditions
1293
+
1294
+ ## Database Schema
1143
1295
  {{SCHEMA_DOC}}
1144
1296
 
1145
- ### Available External Tools
1297
+ ## Available External Tools
1146
1298
  {{AVAILABLE_TOOLS}}
1147
1299
 
1148
- ### Available Components
1149
- {{AVAILABLE_COMPONENTS}}`,
1300
+ ## Available Filter Components
1301
+ {{AVAILABLE_COMPONENTS}}
1302
+
1303
+ ## Existing Dashboard Components
1304
+ {{EXISTING_COMPONENTS}}
1305
+
1306
+ ---
1307
+
1308
+ ## CONTEXT`,
1150
1309
  user: `{{USER_PROMPT}}`
1151
1310
  }
1152
1311
  };
@@ -1854,6 +2013,7 @@ var AuthVerifyRequestMessageSchema = z3.object({
1854
2013
  });
1855
2014
  var UserPromptRequestPayloadSchema = z3.object({
1856
2015
  prompt: z3.string(),
2016
+ userId: z3.string().optional(),
1857
2017
  SA_RUNTIME: z3.object({
1858
2018
  threadId: z3.string(),
1859
2019
  uiBlockId: z3.string()
@@ -1868,6 +2028,7 @@ var UserPromptRequestMessageSchema = z3.object({
1868
2028
  });
1869
2029
  var UserPromptSuggestionsPayloadSchema = z3.object({
1870
2030
  prompt: z3.string(),
2031
+ userId: z3.string().optional(),
1871
2032
  limit: z3.number().int().positive().default(5),
1872
2033
  similarityThreshold: z3.number().min(0).max(1).default(0.4)
1873
2034
  });
@@ -1883,7 +2044,7 @@ var ComponentPropsSchema = z3.object({
1883
2044
  description: z3.string().optional(),
1884
2045
  config: z3.record(z3.unknown()).optional(),
1885
2046
  actions: z3.array(z3.any()).optional()
1886
- });
2047
+ }).passthrough();
1887
2048
  var ComponentSchema = z3.object({
1888
2049
  id: z3.string(),
1889
2050
  name: z3.string(),
@@ -1957,6 +2118,7 @@ var UILogsMessageSchema = z3.object({
1957
2118
  payload: UILogsPayloadSchema
1958
2119
  });
1959
2120
  var ActionsRequestPayloadSchema = z3.object({
2121
+ userId: z3.string().optional(),
1960
2122
  SA_RUNTIME: z3.object({
1961
2123
  threadId: z3.string(),
1962
2124
  uiBlockId: z3.string()
@@ -2157,10 +2319,15 @@ var KbNodesRequestMessageSchema = z3.object({
2157
2319
  });
2158
2320
  var DashCompRequestPayloadSchema = z3.object({
2159
2321
  prompt: z3.string(),
2322
+ userId: z3.string().optional(),
2160
2323
  SA_RUNTIME: z3.object({
2161
2324
  threadId: z3.string().optional(),
2162
2325
  uiBlockId: z3.string().optional()
2163
- }).optional()
2326
+ }).optional(),
2327
+ /** Existing components in the dashboard (for update/filter operations) */
2328
+ existingComponents: z3.array(ComponentSchema).optional(),
2329
+ /** Request type: create (new component), update (modify existing), filter (create filter + update components) */
2330
+ req_type: z3.enum(["create", "update", "filter"]).optional()
2164
2331
  });
2165
2332
  var DashCompRequestMessageSchema = z3.object({
2166
2333
  id: z3.string(),
@@ -3408,9 +3575,9 @@ var PRICING = {
3408
3575
  "gpt-4": { input: 30, output: 60 },
3409
3576
  "gpt-3.5-turbo": { input: 0.5, output: 1.5 },
3410
3577
  // Google Gemini (December 2025)
3411
- "gemini-3-pro": { input: 2, output: 8 },
3578
+ "gemini-3-pro-preview": { input: 2, output: 12 },
3412
3579
  // New Gemini 3
3413
- "gemini-2.5-pro": { input: 1.25, output: 10 },
3580
+ "gemini-3-flash-preview": { input: 0.5, output: 3 },
3414
3581
  // For prompts ≤200K tokens, 2x for >200K
3415
3582
  "gemini-2.5-flash": { input: 0.15, output: 0.6 },
3416
3583
  // Standard mode (thinking disabled: $0.60, thinking enabled: $3.50)
@@ -4595,6 +4762,7 @@ var LLM = class {
4595
4762
  }
4596
4763
  }
4597
4764
  static async _geminiStreamWithTools(messages, tools, toolHandler, modelName, options, maxIterations) {
4765
+ const methodStartTime = Date.now();
4598
4766
  const apiKey = options.apiKey || process.env.GEMINI_API_KEY || "";
4599
4767
  const genAI = new GoogleGenerativeAI(apiKey);
4600
4768
  const systemPrompt = typeof messages.sys === "string" ? messages.sys : messages.sys.map((block) => block.text).join("\n");
@@ -4623,11 +4791,18 @@ var LLM = class {
4623
4791
  let iterations = 0;
4624
4792
  let finalText = "";
4625
4793
  let currentUserMessage = messages.user;
4794
+ let totalToolCalls = 0;
4795
+ let totalInputTokens = 0;
4796
+ let totalOutputTokens = 0;
4626
4797
  while (iterations < maxIterations) {
4627
4798
  iterations++;
4799
+ const iterationStartTime = Date.now();
4800
+ const requestId = llmUsageLogger.generateRequestId();
4628
4801
  const result = await chat.sendMessageStream(currentUserMessage);
4629
4802
  let responseText = "";
4630
4803
  const functionCalls = [];
4804
+ let inputTokens = 0;
4805
+ let outputTokens = 0;
4631
4806
  for await (const chunk of result.stream) {
4632
4807
  const candidate = chunk.candidates?.[0];
4633
4808
  if (!candidate) continue;
@@ -4644,7 +4819,37 @@ var LLM = class {
4644
4819
  });
4645
4820
  }
4646
4821
  }
4822
+ if (chunk.usageMetadata) {
4823
+ inputTokens = chunk.usageMetadata.promptTokenCount || 0;
4824
+ outputTokens = chunk.usageMetadata.candidatesTokenCount || 0;
4825
+ }
4826
+ }
4827
+ const iterationDuration = Date.now() - iterationStartTime;
4828
+ const toolCallsInIteration = functionCalls.length;
4829
+ totalToolCalls += toolCallsInIteration;
4830
+ if (inputTokens === 0) {
4831
+ const userMsg = typeof currentUserMessage === "string" ? currentUserMessage : JSON.stringify(currentUserMessage);
4832
+ inputTokens = Math.ceil((systemPrompt.length + userMsg.length) / 4);
4833
+ }
4834
+ if (outputTokens === 0) {
4835
+ outputTokens = Math.ceil(responseText.length / 4);
4647
4836
  }
4837
+ totalInputTokens += inputTokens;
4838
+ totalOutputTokens += outputTokens;
4839
+ llmUsageLogger.log({
4840
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4841
+ requestId,
4842
+ provider: "gemini",
4843
+ model: modelName,
4844
+ method: `streamWithTools[iter=${iterations}]`,
4845
+ inputTokens,
4846
+ outputTokens,
4847
+ totalTokens: inputTokens + outputTokens,
4848
+ costUSD: llmUsageLogger.calculateCost(modelName, inputTokens, outputTokens),
4849
+ durationMs: iterationDuration,
4850
+ toolCalls: toolCallsInIteration,
4851
+ success: true
4852
+ });
4648
4853
  if (functionCalls.length === 0) {
4649
4854
  finalText = responseText;
4650
4855
  break;
@@ -4677,6 +4882,23 @@ var LLM = class {
4677
4882
  }));
4678
4883
  currentUserMessage = functionResponseParts;
4679
4884
  }
4885
+ const totalDuration = Date.now() - methodStartTime;
4886
+ if (iterations > 1) {
4887
+ llmUsageLogger.log({
4888
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4889
+ requestId: llmUsageLogger.generateRequestId(),
4890
+ provider: "gemini",
4891
+ model: modelName,
4892
+ method: `streamWithTools[TOTAL:${iterations}iters]`,
4893
+ inputTokens: totalInputTokens,
4894
+ outputTokens: totalOutputTokens,
4895
+ totalTokens: totalInputTokens + totalOutputTokens,
4896
+ costUSD: llmUsageLogger.calculateCost(modelName, totalInputTokens, totalOutputTokens),
4897
+ durationMs: totalDuration,
4898
+ toolCalls: totalToolCalls,
4899
+ success: true
4900
+ });
4901
+ }
4680
4902
  if (iterations >= maxIterations) {
4681
4903
  throw new Error(`Max iterations (${maxIterations}) reached in tool calling loop`);
4682
4904
  }
@@ -6731,10 +6953,10 @@ var GeminiLLM = class extends BaseLLM {
6731
6953
  super(config);
6732
6954
  }
6733
6955
  getDefaultModel() {
6734
- return "gemini/gemini-2.5-flash";
6956
+ return "gemini/gemini-3-pro-preview";
6735
6957
  }
6736
6958
  getDefaultFastModel() {
6737
- return "gemini/gemini-2.0-flash-exp";
6959
+ return "gemini/gemini-3-flash-preview";
6738
6960
  }
6739
6961
  getDefaultApiKey() {
6740
6962
  return process.env.GEMINI_API_KEY;
@@ -7248,7 +7470,7 @@ var CONTEXT_CONFIG = {
7248
7470
  };
7249
7471
 
7250
7472
  // src/handlers/user-prompt-request.ts
7251
- var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, userId) => {
7473
+ var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools) => {
7252
7474
  const errors = [];
7253
7475
  logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
7254
7476
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
@@ -7262,6 +7484,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7262
7484
  const userPromptRequest = parseResult.data;
7263
7485
  const { id, payload } = userPromptRequest;
7264
7486
  const prompt = payload.prompt;
7487
+ const userId = payload.userId;
7265
7488
  const SA_RUNTIME = payload.SA_RUNTIME;
7266
7489
  const wsId = userPromptRequest.from.id || "unknown";
7267
7490
  const promptContext = `User Prompt: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
@@ -7434,8 +7657,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7434
7657
  wsId
7435
7658
  };
7436
7659
  };
7437
- async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, userId) {
7438
- const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, userId);
7660
+ async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools) {
7661
+ const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools);
7439
7662
  sendDataResponse4(
7440
7663
  response.id || data.id,
7441
7664
  {
@@ -7467,11 +7690,11 @@ function sendDataResponse4(id, res, sendMessage, clientId) {
7467
7690
 
7468
7691
  // src/handlers/user-prompt-suggestions.ts
7469
7692
  init_logger();
7470
- async function handleUserPromptSuggestions(data, components, sendMessage, collections, userId) {
7693
+ async function handleUserPromptSuggestions(data, components, sendMessage, collections) {
7471
7694
  try {
7472
7695
  const request = UserPromptSuggestionsMessageSchema.parse(data);
7473
7696
  const { id, payload, from } = request;
7474
- const { prompt, limit = 10 } = payload;
7697
+ const { prompt, userId, limit = 10 } = payload;
7475
7698
  const wsId = from.id;
7476
7699
  logger.info(`[USER_PROMPT_SUGGESTIONS_REQ ${id}] Processing user prompt suggestions: ${prompt}`);
7477
7700
  if (!prompt || prompt.trim().length === 0) {
@@ -10111,34 +10334,108 @@ function sendResponse8(id, res, sendMessage, clientId) {
10111
10334
  sendMessage(response);
10112
10335
  }
10113
10336
 
10114
- // src/handlers/dash-comp-request.ts
10337
+ // src/dashComp/index.ts
10115
10338
  init_logger();
10116
- init_prompt_loader();
10117
- async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, _collections, tools) {
10118
- const errors = [];
10119
- let availableComponentsText = "No components available";
10120
- if (components && components.length > 0) {
10121
- availableComponentsText = components.map((comp, idx) => {
10122
- const keywords = comp.keywords ? comp.keywords.join(", ") : "";
10123
- const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
10124
- return `${idx + 1}. ID: ${comp.id}
10339
+
10340
+ // src/dashComp/types.ts
10341
+ var DEFAULT_DASH_COMP_MODELS = {
10342
+ anthropic: "anthropic/claude-haiku-4-5-20251001",
10343
+ gemini: "gemini/gemini-3-flash-preview",
10344
+ openai: "openai/gpt-4o-mini",
10345
+ groq: "groq/llama-3.3-70b-versatile"
10346
+ };
10347
+
10348
+ // src/dashComp/utils.ts
10349
+ function getApiKeyAndModel(anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, dashCompModels) {
10350
+ const providers = llmProviders || ["anthropic", "gemini", "openai", "groq"];
10351
+ let apiKey;
10352
+ let model;
10353
+ if (dashCompModels?.model) {
10354
+ model = dashCompModels.model;
10355
+ const modelProvider = model.split("/")[0];
10356
+ if (modelProvider === "anthropic") apiKey = anthropicApiKey;
10357
+ else if (modelProvider === "gemini") apiKey = geminiApiKey;
10358
+ else if (modelProvider === "openai") apiKey = openaiApiKey;
10359
+ else if (modelProvider === "groq") apiKey = groqApiKey;
10360
+ } else {
10361
+ for (const provider of providers) {
10362
+ if (provider === "anthropic" && anthropicApiKey) {
10363
+ apiKey = anthropicApiKey;
10364
+ model = DEFAULT_DASH_COMP_MODELS.anthropic;
10365
+ break;
10366
+ } else if (provider === "gemini" && geminiApiKey) {
10367
+ apiKey = geminiApiKey;
10368
+ model = DEFAULT_DASH_COMP_MODELS.gemini;
10369
+ break;
10370
+ } else if (provider === "openai" && openaiApiKey) {
10371
+ apiKey = openaiApiKey;
10372
+ model = DEFAULT_DASH_COMP_MODELS.openai;
10373
+ break;
10374
+ } else if (provider === "groq" && groqApiKey) {
10375
+ apiKey = groqApiKey;
10376
+ model = DEFAULT_DASH_COMP_MODELS.groq;
10377
+ break;
10378
+ }
10379
+ }
10380
+ }
10381
+ return { apiKey, model };
10382
+ }
10383
+ function formatComponentsForPrompt(components) {
10384
+ if (!components || components.length === 0) {
10385
+ return "No components available";
10386
+ }
10387
+ return components.map((comp, idx) => {
10388
+ const keywords = comp.keywords ? comp.keywords.join(", ") : "";
10389
+ const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
10390
+ return `${idx + 1}. ID: ${comp.id}
10125
10391
  Name: ${comp.name}
10126
10392
  Type: ${comp.type}
10127
10393
  Description: ${comp.description || "No description"}
10128
10394
  Keywords: ${keywords}
10129
10395
  Props Structure: ${propsPreview}`;
10130
- }).join("\n\n");
10396
+ }).join("\n\n");
10397
+ }
10398
+ function formatToolsForPrompt(tools) {
10399
+ if (!tools || tools.length === 0) {
10400
+ return "No external tools available.";
10131
10401
  }
10132
- let availableToolsText = "No external tools available.";
10133
- if (tools && tools.length > 0) {
10134
- availableToolsText = tools.map((tool, idx) => {
10135
- const paramsStr = Object.entries(tool.params || {}).map(([key, type]) => `${key}: ${type}`).join(", ");
10136
- return `${idx + 1}. ID: ${tool.id}
10402
+ return tools.map((tool, idx) => {
10403
+ const paramsStr = Object.entries(tool.params || {}).map(([key, type]) => `${key}: ${type}`).join(", ");
10404
+ return `${idx + 1}. ID: ${tool.id}
10137
10405
  Name: ${tool.name}
10138
10406
  Description: ${tool.description}
10139
10407
  Parameters: { ${paramsStr} }`;
10140
- }).join("\n\n");
10408
+ }).join("\n\n");
10409
+ }
10410
+ function formatExistingComponentsForPrompt(existingComponents) {
10411
+ if (!existingComponents || existingComponents.length === 0) {
10412
+ return "No existing components in dashboard";
10141
10413
  }
10414
+ return JSON.stringify(existingComponents, null, 2);
10415
+ }
10416
+ function sendDashCompResponse(id, res, sendMessage, clientId) {
10417
+ const response = {
10418
+ id,
10419
+ type: "DASH_COMP_RES",
10420
+ from: { type: "data-agent" },
10421
+ to: {
10422
+ type: "runtime",
10423
+ id: clientId
10424
+ },
10425
+ payload: {
10426
+ ...res
10427
+ }
10428
+ };
10429
+ sendMessage(response);
10430
+ }
10431
+
10432
+ // src/dashComp/pick-component.ts
10433
+ init_logger();
10434
+ init_prompt_loader();
10435
+ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, _collections, tools, dashCompModels) {
10436
+ const errors = [];
10437
+ const availableComponentsText = formatComponentsForPrompt(components);
10438
+ const availableToolsText = formatToolsForPrompt(tools);
10142
10439
  try {
10143
10440
  const schemaDoc = schema.generateSchemaDocumentation();
10144
10441
  const databaseRules = await promptLoader.loadDatabaseRules();
@@ -10150,29 +10447,15 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10150
10447
  AVAILABLE_TOOLS: availableToolsText
10151
10448
  });
10152
10449
  logger.debug("[DASH_COMP_REQ] Loaded dash-comp-picker prompts with schema and tools");
10153
- const providers = llmProviders || ["anthropic", "gemini", "openai", "groq"];
10154
- let apiKey;
10155
- let model = "anthropic/claude-sonnet-4-5-20250929";
10156
- for (const provider of providers) {
10157
- if (provider === "anthropic" && anthropicApiKey) {
10158
- apiKey = anthropicApiKey;
10159
- model = "anthropic/claude-sonnet-4-5-20250929";
10160
- break;
10161
- } else if (provider === "openai" && openaiApiKey) {
10162
- apiKey = openaiApiKey;
10163
- model = "openai/gpt-4o-mini";
10164
- break;
10165
- } else if (provider === "gemini" && geminiApiKey) {
10166
- apiKey = geminiApiKey;
10167
- model = "google/gemini-2.0-flash-001";
10168
- break;
10169
- } else if (provider === "groq" && groqApiKey) {
10170
- apiKey = groqApiKey;
10171
- model = "groq/llama-3.3-70b-versatile";
10172
- break;
10173
- }
10174
- }
10175
- if (!apiKey) {
10450
+ const { apiKey, model } = getApiKeyAndModel(
10451
+ anthropicApiKey,
10452
+ groqApiKey,
10453
+ geminiApiKey,
10454
+ openaiApiKey,
10455
+ llmProviders,
10456
+ dashCompModels
10457
+ );
10458
+ if (!apiKey || !model) {
10176
10459
  errors.push("No API key available for any LLM provider");
10177
10460
  return { success: false, errors };
10178
10461
  }
@@ -10195,11 +10478,21 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10195
10478
  logger.file("[DASH_COMP_REQ] LLM response:", JSON.stringify(result, null, 2));
10196
10479
  if (!result.componentId || !result.props) {
10197
10480
  errors.push("Invalid LLM response: missing componentId or props");
10481
+ userPromptErrorLogger.logError("DASH_COMP_REQ", "Invalid LLM response structure", {
10482
+ prompt,
10483
+ result,
10484
+ missingFields: { componentId: !result.componentId, props: !result.props }
10485
+ });
10198
10486
  return { success: false, errors };
10199
10487
  }
10200
10488
  const originalComponent = components.find((c) => c.id === result.componentId);
10201
10489
  if (!originalComponent) {
10202
10490
  errors.push(`Component ${result.componentId} not found in available components`);
10491
+ userPromptErrorLogger.logError("DASH_COMP_REQ", "Component not found", {
10492
+ prompt,
10493
+ componentId: result.componentId,
10494
+ availableComponentIds: components.map((c) => c.id)
10495
+ });
10203
10496
  return { success: false, errors };
10204
10497
  }
10205
10498
  const finalComponent = {
@@ -10221,18 +10514,102 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10221
10514
  data: {
10222
10515
  component: finalComponent,
10223
10516
  reasoning: result.reasoning || "Component selected based on user prompt",
10224
- dataSource: result.props.query ? "database" : result.props.externalTool ? "external_tool" : "none"
10517
+ dataSource: result.props.query ? "database" : result.props.externalTool ? "external_tool" : "none",
10518
+ isUpdate: result.isUpdate || false
10225
10519
  },
10226
10520
  errors: []
10227
10521
  };
10228
10522
  } catch (error) {
10229
10523
  const errorMsg = error instanceof Error ? error.message : String(error);
10230
10524
  logger.error(`[DASH_COMP_REQ] Error picking component: ${errorMsg}`);
10525
+ userPromptErrorLogger.logError("DASH_COMP_REQ", error instanceof Error ? error : new Error(errorMsg), {
10526
+ prompt,
10527
+ componentsCount: components.length,
10528
+ toolsCount: tools?.length || 0
10529
+ });
10530
+ errors.push(errorMsg);
10531
+ return { success: false, errors };
10532
+ }
10533
+ }
10534
+
10535
+ // src/dashComp/create-filter.ts
10536
+ init_logger();
10537
+ init_prompt_loader();
10538
+ async function createFilterWithLLM(prompt, components, existingComponents, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, tools, dashCompModels) {
10539
+ const errors = [];
10540
+ try {
10541
+ const filterComponents = components.filter((c) => c.type.startsWith("Filter"));
10542
+ if (filterComponents.length === 0) {
10543
+ errors.push("No filter components available");
10544
+ return { success: false, errors };
10545
+ }
10546
+ logger.debug(`[DASH_COMP_REQ:FILTER] Found ${filterComponents.length} filter components`);
10547
+ const schemaDoc = schema.generateSchemaDocumentation();
10548
+ const databaseRules = await promptLoader.loadDatabaseRules();
10549
+ const prompts = await promptLoader.loadPrompts("dash-filter-picker", {
10550
+ USER_PROMPT: prompt,
10551
+ AVAILABLE_COMPONENTS: formatComponentsForPrompt(filterComponents),
10552
+ EXISTING_COMPONENTS: formatExistingComponentsForPrompt(existingComponents),
10553
+ SCHEMA_DOC: schemaDoc || "No database schema available",
10554
+ DATABASE_RULES: databaseRules,
10555
+ AVAILABLE_TOOLS: formatToolsForPrompt(tools)
10556
+ });
10557
+ logger.debug("[DASH_COMP_REQ:FILTER] Loaded dash-filter-picker prompts");
10558
+ const { apiKey, model } = getApiKeyAndModel(
10559
+ anthropicApiKey,
10560
+ groqApiKey,
10561
+ geminiApiKey,
10562
+ openaiApiKey,
10563
+ llmProviders,
10564
+ dashCompModels
10565
+ );
10566
+ if (!apiKey || !model) {
10567
+ errors.push("No API key available for any LLM provider");
10568
+ return { success: false, errors };
10569
+ }
10570
+ logger.info(`[DASH_COMP_REQ:FILTER] Using model: ${model}`);
10571
+ const result = await LLM.stream(
10572
+ { sys: prompts.system, user: prompts.user },
10573
+ { model, maxTokens: 16384, temperature: 0.2, apiKey },
10574
+ true
10575
+ );
10576
+ logger.debug("[DASH_COMP_REQ:FILTER] LLM response received");
10577
+ logger.file("[DASH_COMP_REQ:FILTER] LLM response:", JSON.stringify(result, null, 2));
10578
+ if (!result.filterComponent) {
10579
+ errors.push("Invalid LLM response: missing filterComponent");
10580
+ userPromptErrorLogger.logError("DASH_COMP_REQ:FILTER", "Invalid LLM response structure", {
10581
+ prompt,
10582
+ result,
10583
+ missingFields: { filterComponent: !result.filterComponent }
10584
+ });
10585
+ return { success: false, errors };
10586
+ }
10587
+ logger.info(`[DASH_COMP_REQ:FILTER] Successfully created filter: ${result.filterComponent.componentType}`);
10588
+ logger.info(`[DASH_COMP_REQ:FILTER] Updated ${result.updatedComponents?.length || 0} components`);
10589
+ return {
10590
+ success: true,
10591
+ data: {
10592
+ filterComponent: result.filterComponent,
10593
+ updatedComponents: result.updatedComponents || [],
10594
+ filterBindings: result.filterBindings || {},
10595
+ reasoning: result.reasoning || "Filter created based on user prompt"
10596
+ },
10597
+ errors: []
10598
+ };
10599
+ } catch (error) {
10600
+ const errorMsg = error instanceof Error ? error.message : String(error);
10601
+ logger.error(`[DASH_COMP_REQ:FILTER] Error creating filter: ${errorMsg}`);
10602
+ userPromptErrorLogger.logError("DASH_COMP_REQ:FILTER", error instanceof Error ? error : new Error(errorMsg), {
10603
+ prompt,
10604
+ existingComponentsCount: existingComponents.length
10605
+ });
10231
10606
  errors.push(errorMsg);
10232
10607
  return { success: false, errors };
10233
10608
  }
10234
10609
  }
10235
- var processDashCompRequest = async (data, components, _sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools) => {
10610
+
10611
+ // src/dashComp/index.ts
10612
+ var processDashCompRequest = async (data, components, _sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools, dashCompModels) => {
10236
10613
  const errors = [];
10237
10614
  logger.debug("[DASH_COMP_REQ] Parsing incoming message data");
10238
10615
  const parseResult = DashCompRequestMessageSchema.safeParse(data);
@@ -10246,15 +10623,25 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10246
10623
  const dashCompRequest = parseResult.data;
10247
10624
  const { id, payload } = dashCompRequest;
10248
10625
  const prompt = payload.prompt;
10626
+ const reqType = payload.req_type || "create";
10627
+ const existingComponents = payload.existingComponents || [];
10249
10628
  const wsId = dashCompRequest.from.id || "unknown";
10629
+ const promptContext = `DASH_COMP[${reqType}]: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
10630
+ llmUsageLogger.resetLogFile(promptContext);
10250
10631
  if (!prompt) {
10251
10632
  errors.push("Prompt is required");
10252
10633
  }
10634
+ if (reqType === "filter" && existingComponents.length === 0) {
10635
+ errors.push("Filter request requires existingComponents");
10636
+ }
10253
10637
  if (errors.length > 0) {
10254
10638
  return { success: false, errors, id, wsId };
10255
10639
  }
10256
- logger.info(`[DASH_COMP_REQ] Processing request for prompt: "${prompt.substring(0, 50)}..."`);
10640
+ logger.info(`[DASH_COMP_REQ] Processing ${reqType} request for prompt: "${prompt.substring(0, 50)}..."`);
10257
10641
  logger.info(`[DASH_COMP_REQ] Available: ${components?.length || 0} components, ${tools?.length || 0} tools`);
10642
+ if (existingComponents.length > 0) {
10643
+ logger.info(`[DASH_COMP_REQ] Existing components in dashboard: ${existingComponents.length}`);
10644
+ }
10258
10645
  if (!components || components.length === 0) {
10259
10646
  logger.warn("[DASH_COMP_REQ] No components available");
10260
10647
  return {
@@ -10264,17 +10651,35 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10264
10651
  wsId
10265
10652
  };
10266
10653
  }
10267
- const llmResponse = await pickComponentWithLLM(
10268
- prompt,
10269
- components,
10270
- anthropicApiKey,
10271
- groqApiKey,
10272
- geminiApiKey,
10273
- openaiApiKey,
10274
- llmProviders,
10275
- collections,
10276
- tools
10277
- );
10654
+ let llmResponse;
10655
+ if (reqType === "filter") {
10656
+ llmResponse = await createFilterWithLLM(
10657
+ prompt,
10658
+ components,
10659
+ existingComponents,
10660
+ anthropicApiKey,
10661
+ groqApiKey,
10662
+ geminiApiKey,
10663
+ openaiApiKey,
10664
+ llmProviders,
10665
+ tools,
10666
+ dashCompModels
10667
+ );
10668
+ } else {
10669
+ llmResponse = await pickComponentWithLLM(
10670
+ prompt,
10671
+ components,
10672
+ anthropicApiKey,
10673
+ groqApiKey,
10674
+ geminiApiKey,
10675
+ openaiApiKey,
10676
+ llmProviders,
10677
+ collections,
10678
+ tools,
10679
+ dashCompModels
10680
+ );
10681
+ }
10682
+ llmUsageLogger.logSessionSummary(`DASH_COMP[${reqType}]: ${prompt?.substring(0, 30)}`);
10278
10683
  return {
10279
10684
  success: llmResponse.success,
10280
10685
  data: llmResponse.data,
@@ -10283,7 +10688,7 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10283
10688
  wsId
10284
10689
  };
10285
10690
  };
10286
- async function handleDashCompRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools) {
10691
+ async function handleDashCompRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools, dashCompModels) {
10287
10692
  const response = await processDashCompRequest(
10288
10693
  data,
10289
10694
  components,
@@ -10294,7 +10699,8 @@ async function handleDashCompRequest(data, components, sendMessage, anthropicApi
10294
10699
  openaiApiKey,
10295
10700
  llmProviders,
10296
10701
  collections,
10297
- tools
10702
+ tools,
10703
+ dashCompModels
10298
10704
  );
10299
10705
  sendDashCompResponse(
10300
10706
  response.id || data.id,
@@ -10306,22 +10712,7 @@ async function handleDashCompRequest(data, components, sendMessage, anthropicApi
10306
10712
  sendMessage,
10307
10713
  response.wsId || data.from?.id
10308
10714
  );
10309
- }
10310
- function sendDashCompResponse(id, res, sendMessage, clientId) {
10311
- const response = {
10312
- id,
10313
- type: "DASH_COMP_RES",
10314
- from: { type: "data-agent" },
10315
- to: {
10316
- type: "runtime",
10317
- id: clientId
10318
- },
10319
- payload: {
10320
- ...res
10321
- }
10322
- };
10323
- sendMessage(response);
10324
- logger.info(`[DASH_COMP_REQ] Response sent to client ${clientId}`);
10715
+ logger.info(`[DASH_COMP_REQ] Response sent to client ${response.wsId || data.from?.id}`);
10325
10716
  }
10326
10717
 
10327
10718
  // src/auth/user-manager.ts
@@ -11169,7 +11560,6 @@ var SuperatomSDK = class {
11169
11560
  }
11170
11561
  this.apiKey = config.apiKey;
11171
11562
  this.projectId = config.projectId;
11172
- this.userId = config.userId || "anonymous";
11173
11563
  this.type = config.type || "data-agent";
11174
11564
  this.bundleDir = config.bundleDir;
11175
11565
  this.url = config.url || process.env.SA_WEBSOCKET_URL || DEFAULT_WS_URL;
@@ -11271,7 +11661,6 @@ var SuperatomSDK = class {
11271
11661
  url.searchParams.set("apiKey", this.apiKey);
11272
11662
  }
11273
11663
  url.searchParams.set("projectId", this.projectId);
11274
- url.searchParams.set("userId", this.userId);
11275
11664
  url.searchParams.set("type", this.type);
11276
11665
  logger.info(`Connecting to WebSocket: ${url.toString()}`);
11277
11666
  this.ws = createWebSocket(url.toString());
@@ -11332,7 +11721,7 @@ var SuperatomSDK = class {
11332
11721
  });
11333
11722
  break;
11334
11723
  case "USER_PROMPT_REQ":
11335
- handleUserPromptRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.geminiApiKey, this.openaiApiKey, this.llmProviders, this.collections, this.tools, this.userId).catch((error) => {
11724
+ handleUserPromptRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.geminiApiKey, this.openaiApiKey, this.llmProviders, this.collections, this.tools).catch((error) => {
11336
11725
  logger.error("Failed to handle user prompt request:", error);
11337
11726
  });
11338
11727
  break;
@@ -11342,7 +11731,7 @@ var SuperatomSDK = class {
11342
11731
  });
11343
11732
  break;
11344
11733
  case "USER_PROMPT_SUGGESTIONS_REQ":
11345
- handleUserPromptSuggestions(parsed, this.components, (msg) => this.send(msg), this.collections, this.userId).catch((error) => {
11734
+ handleUserPromptSuggestions(parsed, this.components, (msg) => this.send(msg), this.collections).catch((error) => {
11346
11735
  logger.error("Failed to handle user prompt suggestions request:", error);
11347
11736
  });
11348
11737
  break;