@superatomai/sdk-node 0.0.42 → 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
1219
+
1220
+ Use this binding format to connect filter values to component params:
1221
+ \`\`\`json
1222
+ {
1223
+ "paramName": "$filter.filterId.value"
1224
+ }
1225
+ \`\`\`
1141
1226
 
1142
- ### Database Schema
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
  });
@@ -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(),
@@ -7303,7 +7470,7 @@ var CONTEXT_CONFIG = {
7303
7470
  };
7304
7471
 
7305
7472
  // src/handlers/user-prompt-request.ts
7306
- 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) => {
7307
7474
  const errors = [];
7308
7475
  logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
7309
7476
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
@@ -7317,6 +7484,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7317
7484
  const userPromptRequest = parseResult.data;
7318
7485
  const { id, payload } = userPromptRequest;
7319
7486
  const prompt = payload.prompt;
7487
+ const userId = payload.userId;
7320
7488
  const SA_RUNTIME = payload.SA_RUNTIME;
7321
7489
  const wsId = userPromptRequest.from.id || "unknown";
7322
7490
  const promptContext = `User Prompt: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
@@ -7489,8 +7657,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7489
7657
  wsId
7490
7658
  };
7491
7659
  };
7492
- async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, userId) {
7493
- 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);
7494
7662
  sendDataResponse4(
7495
7663
  response.id || data.id,
7496
7664
  {
@@ -7522,11 +7690,11 @@ function sendDataResponse4(id, res, sendMessage, clientId) {
7522
7690
 
7523
7691
  // src/handlers/user-prompt-suggestions.ts
7524
7692
  init_logger();
7525
- async function handleUserPromptSuggestions(data, components, sendMessage, collections, userId) {
7693
+ async function handleUserPromptSuggestions(data, components, sendMessage, collections) {
7526
7694
  try {
7527
7695
  const request = UserPromptSuggestionsMessageSchema.parse(data);
7528
7696
  const { id, payload, from } = request;
7529
- const { prompt, limit = 10 } = payload;
7697
+ const { prompt, userId, limit = 10 } = payload;
7530
7698
  const wsId = from.id;
7531
7699
  logger.info(`[USER_PROMPT_SUGGESTIONS_REQ ${id}] Processing user prompt suggestions: ${prompt}`);
7532
7700
  if (!prompt || prompt.trim().length === 0) {
@@ -10166,40 +10334,108 @@ function sendResponse8(id, res, sendMessage, clientId) {
10166
10334
  sendMessage(response);
10167
10335
  }
10168
10336
 
10169
- // src/handlers/dash-comp-request.ts
10337
+ // src/dashComp/index.ts
10170
10338
  init_logger();
10171
- init_prompt_loader();
10339
+
10340
+ // src/dashComp/types.ts
10172
10341
  var DEFAULT_DASH_COMP_MODELS = {
10173
10342
  anthropic: "anthropic/claude-haiku-4-5-20251001",
10174
10343
  gemini: "gemini/gemini-3-flash-preview",
10175
10344
  openai: "openai/gpt-4o-mini",
10176
10345
  groq: "groq/llama-3.3-70b-versatile"
10177
10346
  };
10178
- async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, _collections, tools, dashCompModels) {
10179
- const errors = [];
10180
- let availableComponentsText = "No components available";
10181
- if (components && components.length > 0) {
10182
- availableComponentsText = components.map((comp, idx) => {
10183
- const keywords = comp.keywords ? comp.keywords.join(", ") : "";
10184
- const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
10185
- return `${idx + 1}. ID: ${comp.id}
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}
10186
10391
  Name: ${comp.name}
10187
10392
  Type: ${comp.type}
10188
10393
  Description: ${comp.description || "No description"}
10189
10394
  Keywords: ${keywords}
10190
10395
  Props Structure: ${propsPreview}`;
10191
- }).join("\n\n");
10396
+ }).join("\n\n");
10397
+ }
10398
+ function formatToolsForPrompt(tools) {
10399
+ if (!tools || tools.length === 0) {
10400
+ return "No external tools available.";
10192
10401
  }
10193
- let availableToolsText = "No external tools available.";
10194
- if (tools && tools.length > 0) {
10195
- availableToolsText = tools.map((tool, idx) => {
10196
- const paramsStr = Object.entries(tool.params || {}).map(([key, type]) => `${key}: ${type}`).join(", ");
10197
- 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}
10198
10405
  Name: ${tool.name}
10199
10406
  Description: ${tool.description}
10200
10407
  Parameters: { ${paramsStr} }`;
10201
- }).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";
10202
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);
10203
10439
  try {
10204
10440
  const schemaDoc = schema.generateSchemaDocumentation();
10205
10441
  const databaseRules = await promptLoader.loadDatabaseRules();
@@ -10211,38 +10447,14 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10211
10447
  AVAILABLE_TOOLS: availableToolsText
10212
10448
  });
10213
10449
  logger.debug("[DASH_COMP_REQ] Loaded dash-comp-picker prompts with schema and tools");
10214
- const providers = llmProviders || ["anthropic", "gemini", "openai", "groq"];
10215
- let apiKey;
10216
- let model;
10217
- if (dashCompModels?.model) {
10218
- model = dashCompModels.model;
10219
- const modelProvider = model.split("/")[0];
10220
- if (modelProvider === "anthropic") apiKey = anthropicApiKey;
10221
- else if (modelProvider === "gemini") apiKey = geminiApiKey;
10222
- else if (modelProvider === "openai") apiKey = openaiApiKey;
10223
- else if (modelProvider === "groq") apiKey = groqApiKey;
10224
- logger.info(`[DASH_COMP_REQ] Using configured model: ${model}`);
10225
- } else {
10226
- for (const provider of providers) {
10227
- if (provider === "anthropic" && anthropicApiKey) {
10228
- apiKey = anthropicApiKey;
10229
- model = DEFAULT_DASH_COMP_MODELS.anthropic;
10230
- break;
10231
- } else if (provider === "gemini" && geminiApiKey) {
10232
- apiKey = geminiApiKey;
10233
- model = DEFAULT_DASH_COMP_MODELS.gemini;
10234
- break;
10235
- } else if (provider === "openai" && openaiApiKey) {
10236
- apiKey = openaiApiKey;
10237
- model = DEFAULT_DASH_COMP_MODELS.openai;
10238
- break;
10239
- } else if (provider === "groq" && groqApiKey) {
10240
- apiKey = groqApiKey;
10241
- model = DEFAULT_DASH_COMP_MODELS.groq;
10242
- break;
10243
- }
10244
- }
10245
- }
10450
+ const { apiKey, model } = getApiKeyAndModel(
10451
+ anthropicApiKey,
10452
+ groqApiKey,
10453
+ geminiApiKey,
10454
+ openaiApiKey,
10455
+ llmProviders,
10456
+ dashCompModels
10457
+ );
10246
10458
  if (!apiKey || !model) {
10247
10459
  errors.push("No API key available for any LLM provider");
10248
10460
  return { success: false, errors };
@@ -10302,7 +10514,8 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10302
10514
  data: {
10303
10515
  component: finalComponent,
10304
10516
  reasoning: result.reasoning || "Component selected based on user prompt",
10305
- 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
10306
10519
  },
10307
10520
  errors: []
10308
10521
  };
@@ -10318,6 +10531,84 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10318
10531
  return { success: false, errors };
10319
10532
  }
10320
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
+ });
10606
+ errors.push(errorMsg);
10607
+ return { success: false, errors };
10608
+ }
10609
+ }
10610
+
10611
+ // src/dashComp/index.ts
10321
10612
  var processDashCompRequest = async (data, components, _sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools, dashCompModels) => {
10322
10613
  const errors = [];
10323
10614
  logger.debug("[DASH_COMP_REQ] Parsing incoming message data");
@@ -10332,17 +10623,25 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10332
10623
  const dashCompRequest = parseResult.data;
10333
10624
  const { id, payload } = dashCompRequest;
10334
10625
  const prompt = payload.prompt;
10626
+ const reqType = payload.req_type || "create";
10627
+ const existingComponents = payload.existingComponents || [];
10335
10628
  const wsId = dashCompRequest.from.id || "unknown";
10336
- const promptContext = `DASH_COMP: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
10629
+ const promptContext = `DASH_COMP[${reqType}]: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
10337
10630
  llmUsageLogger.resetLogFile(promptContext);
10338
10631
  if (!prompt) {
10339
10632
  errors.push("Prompt is required");
10340
10633
  }
10634
+ if (reqType === "filter" && existingComponents.length === 0) {
10635
+ errors.push("Filter request requires existingComponents");
10636
+ }
10341
10637
  if (errors.length > 0) {
10342
10638
  return { success: false, errors, id, wsId };
10343
10639
  }
10344
- 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)}..."`);
10345
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
+ }
10346
10645
  if (!components || components.length === 0) {
10347
10646
  logger.warn("[DASH_COMP_REQ] No components available");
10348
10647
  return {
@@ -10352,19 +10651,35 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10352
10651
  wsId
10353
10652
  };
10354
10653
  }
10355
- const llmResponse = await pickComponentWithLLM(
10356
- prompt,
10357
- components,
10358
- anthropicApiKey,
10359
- groqApiKey,
10360
- geminiApiKey,
10361
- openaiApiKey,
10362
- llmProviders,
10363
- collections,
10364
- tools,
10365
- dashCompModels
10366
- );
10367
- llmUsageLogger.logSessionSummary(`DASH_COMP: ${prompt?.substring(0, 30)}`);
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)}`);
10368
10683
  return {
10369
10684
  success: llmResponse.success,
10370
10685
  data: llmResponse.data,
@@ -10397,22 +10712,7 @@ async function handleDashCompRequest(data, components, sendMessage, anthropicApi
10397
10712
  sendMessage,
10398
10713
  response.wsId || data.from?.id
10399
10714
  );
10400
- }
10401
- function sendDashCompResponse(id, res, sendMessage, clientId) {
10402
- const response = {
10403
- id,
10404
- type: "DASH_COMP_RES",
10405
- from: { type: "data-agent" },
10406
- to: {
10407
- type: "runtime",
10408
- id: clientId
10409
- },
10410
- payload: {
10411
- ...res
10412
- }
10413
- };
10414
- sendMessage(response);
10415
- 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}`);
10416
10716
  }
10417
10717
 
10418
10718
  // src/auth/user-manager.ts
@@ -11260,7 +11560,6 @@ var SuperatomSDK = class {
11260
11560
  }
11261
11561
  this.apiKey = config.apiKey;
11262
11562
  this.projectId = config.projectId;
11263
- this.userId = config.userId || "anonymous";
11264
11563
  this.type = config.type || "data-agent";
11265
11564
  this.bundleDir = config.bundleDir;
11266
11565
  this.url = config.url || process.env.SA_WEBSOCKET_URL || DEFAULT_WS_URL;
@@ -11362,7 +11661,6 @@ var SuperatomSDK = class {
11362
11661
  url.searchParams.set("apiKey", this.apiKey);
11363
11662
  }
11364
11663
  url.searchParams.set("projectId", this.projectId);
11365
- url.searchParams.set("userId", this.userId);
11366
11664
  url.searchParams.set("type", this.type);
11367
11665
  logger.info(`Connecting to WebSocket: ${url.toString()}`);
11368
11666
  this.ws = createWebSocket(url.toString());
@@ -11423,7 +11721,7 @@ var SuperatomSDK = class {
11423
11721
  });
11424
11722
  break;
11425
11723
  case "USER_PROMPT_REQ":
11426
- 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) => {
11427
11725
  logger.error("Failed to handle user prompt request:", error);
11428
11726
  });
11429
11727
  break;
@@ -11433,7 +11731,7 @@ var SuperatomSDK = class {
11433
11731
  });
11434
11732
  break;
11435
11733
  case "USER_PROMPT_SUGGESTIONS_REQ":
11436
- 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) => {
11437
11735
  logger.error("Failed to handle user prompt suggestions request:", error);
11438
11736
  });
11439
11737
  break;