@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.js CHANGED
@@ -1050,11 +1050,29 @@ Analyze the user's request and:
1050
1050
  2. **Match by Type**: Choose the component type that best fits the data visualization or action need
1051
1051
  3. **Match by Description**: Use component descriptions and keywords to find the best fit
1052
1052
 
1053
+ ## Component Update Handling
1054
+
1055
+ The user prompt may contain an **existing component** to update. Detect this by looking for:
1056
+ - JSON object with \`componentId\`, \`props\`, or similar component structure in the prompt
1057
+ - Phrases like "update this", "modify", "change", "edit this component"
1058
+
1059
+ ### When UPDATING an existing component:
1060
+ 1. **Preserve the \`componentId\`** from the current component (do NOT pick a new one)
1061
+ 2. **Keep the same \`componentType\`** unless the user explicitly asks to change it
1062
+ 3. **Merge props**: Start with existing props, then modify only what the user requested
1063
+ 4. **Set \`isUpdate: true\`** in your response
1064
+ 5. **Preserve unmentioned props**: If user only asks to change the query, keep title/config unchanged
1065
+
1066
+ ### When CREATING a new component:
1067
+ 1. Pick the best component from the available list
1068
+ 2. Generate all props from scratch
1069
+ 3. Set \`isUpdate: false\` in your response
1070
+
1053
1071
  ## Data Source Decision
1054
1072
 
1055
1073
  ### Use DATABASE when:
1056
- - User asks about data that exists in the database schema (customers, orders, products, etc.)
1057
- - Questions about internal business data (sales, inventory, users, transactions)
1074
+ - User asks about data that exists in the database schema
1075
+ - Questions about internal business data
1058
1076
  - CRUD operations on database tables
1059
1077
 
1060
1078
  ### Use EXTERNAL TOOL when:
@@ -1135,11 +1153,12 @@ Analyze the user's request and:
1135
1153
  You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1136
1154
 
1137
1155
  {
1138
- "componentId": "id_from_available_list",
1156
+ "componentId": "id_from_available_list_or_existing_component_id",
1139
1157
  "componentName": "name_of_component",
1140
1158
  "componentType": "type_of_component",
1141
1159
  "dataSourceType": "database" | "external_tool",
1142
1160
  "operationType": "view" | "create" | "update" | "delete",
1161
+ "isUpdate": true | false,
1143
1162
  "reasoning": "Why this component was selected and why this data source",
1144
1163
  "props": {
1145
1164
  // Generate ALL props based on the component's Props Structure
@@ -1150,25 +1169,165 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1150
1169
 
1151
1170
  **CRITICAL:**
1152
1171
  - Return ONLY valid JSON (no markdown code blocks, no text before/after)
1153
- - \`componentId\` MUST match an ID from the available components list
1172
+ - \`componentId\`: For new components, MUST match an ID from the available components list. For updates, preserve the existing component's ID
1173
+ - \`isUpdate\`: Set to \`true\` if updating an existing component, \`false\` if creating new
1154
1174
  - \`dataSourceType\` indicates whether data comes from database or external tool
1155
- - \`operationType\` indicates the type of operation (view/create/update/delete)
1175
+ - \`operationType\` indicates the type of data operation (view/create/update/delete)
1156
1176
  - Generate COMPLETE props based on the component's "Props Structure"
1157
1177
  - For queries, ALWAYS use \`$paramName\` placeholders and include \`params\` object
1158
1178
  - For external tools, \`toolId\` MUST match an ID from the available tools list
1159
1179
 
1180
+ ## Database Schema
1181
+ {{SCHEMA_DOC}}
1182
+
1183
+ ## Available External Tools
1184
+ {{AVAILABLE_TOOLS}}
1185
+
1186
+ ## Available Components
1187
+ {{AVAILABLE_COMPONENTS}}
1188
+
1160
1189
  ---
1161
1190
 
1162
- ## CONTEXT (for this specific request)
1191
+ ## CONTEXT`,
1192
+ user: `{{USER_PROMPT}}`
1193
+ },
1194
+ "dash-filter-picker": {
1195
+ system: `You are a dashboard filter expert that creates filter components and updates existing dashboard components to work with the filter.
1196
+
1197
+ ## Your Task
1198
+
1199
+ 1. **Create a filter component** based on the user's request (DatePicker, Dropdown, SearchBox, etc.)
1200
+ 2. **Update all existing components** to use the filter values in their queries/params
1201
+
1202
+ ## Filter Types
1203
+
1204
+ Choose the appropriate filter component based on user intent:
1205
+ - **DateRangePicker**: For date range filtering (start date, end date)
1206
+ - **DatePicker**: For single date filtering
1207
+ - **Dropdown**: For categorical filtering (status, category, type, etc.)
1208
+ - **MultiSelect**: For multiple value selection
1209
+ - **SearchBox**: For text search filtering
1210
+ - **NumberRange**: For numeric range filtering
1211
+
1212
+ ## Filter Component Structure
1213
+
1214
+ Generate a filter component with these props:
1215
+ \`\`\`json
1216
+ {
1217
+ "componentId": "unique_filter_id",
1218
+ "componentType": "DateRangePicker | Dropdown | SearchBox | etc.",
1219
+ "componentName": "Display Name",
1220
+ "props": {
1221
+ "filterId": "unique_filter_id",
1222
+ "label": "Filter Label",
1223
+ "defaultValue": "optional default value",
1224
+ "options": []
1225
+ }
1226
+ }
1227
+ \`\`\`
1228
+
1229
+ ## Updating Existing Components
1230
+
1231
+ For each existing component, update its query/externalTool to use the filter:
1232
+
1233
+ ### For Database Queries:
1234
+ - Add filter conditions to WHERE clause using \`$paramName\` placeholders
1235
+ - Add the filter param to the \`params\` object with binding reference
1236
+
1237
+ ### For External Tools:
1238
+ - Add filter params to the tool's params object with binding reference
1239
+
1240
+ ## Filter Bindings
1241
+
1242
+ Use this binding format to connect filter values to component params:
1243
+ \`\`\`json
1244
+ {
1245
+ "paramName": "$filter.filterId.value"
1246
+ }
1247
+ \`\`\`
1163
1248
 
1164
- ### Database Schema
1249
+ For DateRangePicker:
1250
+ - \`$filter.filterId.startDate\`
1251
+ - \`$filter.filterId.endDate\`
1252
+
1253
+ For Dropdown/MultiSelect:
1254
+ - \`$filter.filterId.value\`
1255
+
1256
+ For SearchBox:
1257
+ - \`$filter.filterId.searchText\`
1258
+
1259
+ ### Database Query Rules
1260
+ {{DATABASE_RULES}}
1261
+
1262
+ ## Output Format
1263
+
1264
+ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1265
+
1266
+ {
1267
+ "filterComponent": {
1268
+ "componentId": "filter_unique_id",
1269
+ "componentType": "DateRangePicker | Dropdown | etc.",
1270
+ "componentName": "Filter Display Name",
1271
+ "props": {
1272
+ "filterId": "filter_unique_id",
1273
+ "label": "Filter Label",
1274
+ "defaultValue": null,
1275
+ "options": []
1276
+ }
1277
+ },
1278
+ "updatedComponents": [
1279
+ {
1280
+ "componentId": "existing_component_id",
1281
+ "componentType": "existing_type",
1282
+ "componentName": "existing_name",
1283
+ "props": {
1284
+ // RETURN THE COMPLETE PROPS OBJECT
1285
+ // Copy ALL existing props and only modify the necessary fields
1286
+ "title": "Existing Title",
1287
+ "description": "Existing Description",
1288
+ "config": {},
1289
+ "query": {
1290
+ "sql": "SELECT ... WHERE column BETWEEN $startDate AND $endDate",
1291
+ "params": {
1292
+ "existingParam": "existing_value",
1293
+ "startDate": "$filter.filterId.startDate",
1294
+ "endDate": "$filter.filterId.endDate"
1295
+ }
1296
+ }
1297
+ }
1298
+ }
1299
+ ],
1300
+ "filterBindings": {
1301
+ "startDate": "$filter.filterId.startDate",
1302
+ "endDate": "$filter.filterId.endDate"
1303
+ },
1304
+ "reasoning": "Explanation of filter choice and how components were updated"
1305
+ }
1306
+
1307
+ **CRITICAL:**
1308
+ - Return ONLY valid JSON (no markdown code blocks, no text before/after)
1309
+ - **RETURN COMPLETE PROPS**: Copy ALL existing props from each component, only modify what's needed for the filter
1310
+ - Do NOT omit existing props like title, description, config - include them unchanged
1311
+ - Only modify query.sql (add WHERE conditions) and query.params (add filter bindings)
1312
+ - For externalTool, only add filter params to the params object
1313
+ - Use consistent param naming across all components
1314
+ - Ensure SQL syntax is valid with the new filter conditions
1315
+
1316
+ ## Database Schema
1165
1317
  {{SCHEMA_DOC}}
1166
1318
 
1167
- ### Available External Tools
1319
+ ## Available External Tools
1168
1320
  {{AVAILABLE_TOOLS}}
1169
1321
 
1170
- ### Available Components
1171
- {{AVAILABLE_COMPONENTS}}`,
1322
+ ## Available Filter Components
1323
+ {{AVAILABLE_COMPONENTS}}
1324
+
1325
+ ## Existing Dashboard Components
1326
+ {{EXISTING_COMPONENTS}}
1327
+
1328
+ ---
1329
+
1330
+ ## CONTEXT`,
1172
1331
  user: `{{USER_PROMPT}}`
1173
1332
  }
1174
1333
  };
@@ -1904,6 +2063,7 @@ var AuthVerifyRequestMessageSchema = import_zod3.z.object({
1904
2063
  });
1905
2064
  var UserPromptRequestPayloadSchema = import_zod3.z.object({
1906
2065
  prompt: import_zod3.z.string(),
2066
+ userId: import_zod3.z.string().optional(),
1907
2067
  SA_RUNTIME: import_zod3.z.object({
1908
2068
  threadId: import_zod3.z.string(),
1909
2069
  uiBlockId: import_zod3.z.string()
@@ -1918,6 +2078,7 @@ var UserPromptRequestMessageSchema = import_zod3.z.object({
1918
2078
  });
1919
2079
  var UserPromptSuggestionsPayloadSchema = import_zod3.z.object({
1920
2080
  prompt: import_zod3.z.string(),
2081
+ userId: import_zod3.z.string().optional(),
1921
2082
  limit: import_zod3.z.number().int().positive().default(5),
1922
2083
  similarityThreshold: import_zod3.z.number().min(0).max(1).default(0.4)
1923
2084
  });
@@ -2007,6 +2168,7 @@ var UILogsMessageSchema = import_zod3.z.object({
2007
2168
  payload: UILogsPayloadSchema
2008
2169
  });
2009
2170
  var ActionsRequestPayloadSchema = import_zod3.z.object({
2171
+ userId: import_zod3.z.string().optional(),
2010
2172
  SA_RUNTIME: import_zod3.z.object({
2011
2173
  threadId: import_zod3.z.string(),
2012
2174
  uiBlockId: import_zod3.z.string()
@@ -2207,10 +2369,15 @@ var KbNodesRequestMessageSchema = import_zod3.z.object({
2207
2369
  });
2208
2370
  var DashCompRequestPayloadSchema = import_zod3.z.object({
2209
2371
  prompt: import_zod3.z.string(),
2372
+ userId: import_zod3.z.string().optional(),
2210
2373
  SA_RUNTIME: import_zod3.z.object({
2211
2374
  threadId: import_zod3.z.string().optional(),
2212
2375
  uiBlockId: import_zod3.z.string().optional()
2213
- }).optional()
2376
+ }).optional(),
2377
+ /** Existing components in the dashboard (for update/filter operations) */
2378
+ existingComponents: import_zod3.z.array(ComponentSchema).optional(),
2379
+ /** Request type: create (new component), update (modify existing), filter (create filter + update components) */
2380
+ req_type: import_zod3.z.enum(["create", "update", "filter"]).optional()
2214
2381
  });
2215
2382
  var DashCompRequestMessageSchema = import_zod3.z.object({
2216
2383
  id: import_zod3.z.string(),
@@ -7353,7 +7520,7 @@ var CONTEXT_CONFIG = {
7353
7520
  };
7354
7521
 
7355
7522
  // src/handlers/user-prompt-request.ts
7356
- var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, userId) => {
7523
+ var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools) => {
7357
7524
  const errors = [];
7358
7525
  logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
7359
7526
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
@@ -7367,6 +7534,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7367
7534
  const userPromptRequest = parseResult.data;
7368
7535
  const { id, payload } = userPromptRequest;
7369
7536
  const prompt = payload.prompt;
7537
+ const userId = payload.userId;
7370
7538
  const SA_RUNTIME = payload.SA_RUNTIME;
7371
7539
  const wsId = userPromptRequest.from.id || "unknown";
7372
7540
  const promptContext = `User Prompt: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
@@ -7539,8 +7707,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7539
7707
  wsId
7540
7708
  };
7541
7709
  };
7542
- async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, userId) {
7543
- const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, userId);
7710
+ async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools) {
7711
+ const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools);
7544
7712
  sendDataResponse4(
7545
7713
  response.id || data.id,
7546
7714
  {
@@ -7572,11 +7740,11 @@ function sendDataResponse4(id, res, sendMessage, clientId) {
7572
7740
 
7573
7741
  // src/handlers/user-prompt-suggestions.ts
7574
7742
  init_logger();
7575
- async function handleUserPromptSuggestions(data, components, sendMessage, collections, userId) {
7743
+ async function handleUserPromptSuggestions(data, components, sendMessage, collections) {
7576
7744
  try {
7577
7745
  const request = UserPromptSuggestionsMessageSchema.parse(data);
7578
7746
  const { id, payload, from } = request;
7579
- const { prompt, limit = 10 } = payload;
7747
+ const { prompt, userId, limit = 10 } = payload;
7580
7748
  const wsId = from.id;
7581
7749
  logger.info(`[USER_PROMPT_SUGGESTIONS_REQ ${id}] Processing user prompt suggestions: ${prompt}`);
7582
7750
  if (!prompt || prompt.trim().length === 0) {
@@ -10216,40 +10384,108 @@ function sendResponse8(id, res, sendMessage, clientId) {
10216
10384
  sendMessage(response);
10217
10385
  }
10218
10386
 
10219
- // src/handlers/dash-comp-request.ts
10387
+ // src/dashComp/index.ts
10220
10388
  init_logger();
10221
- init_prompt_loader();
10389
+
10390
+ // src/dashComp/types.ts
10222
10391
  var DEFAULT_DASH_COMP_MODELS = {
10223
10392
  anthropic: "anthropic/claude-haiku-4-5-20251001",
10224
10393
  gemini: "gemini/gemini-3-flash-preview",
10225
10394
  openai: "openai/gpt-4o-mini",
10226
10395
  groq: "groq/llama-3.3-70b-versatile"
10227
10396
  };
10228
- async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, _collections, tools, dashCompModels) {
10229
- const errors = [];
10230
- let availableComponentsText = "No components available";
10231
- if (components && components.length > 0) {
10232
- availableComponentsText = components.map((comp, idx) => {
10233
- const keywords = comp.keywords ? comp.keywords.join(", ") : "";
10234
- const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
10235
- return `${idx + 1}. ID: ${comp.id}
10397
+
10398
+ // src/dashComp/utils.ts
10399
+ function getApiKeyAndModel(anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, dashCompModels) {
10400
+ const providers = llmProviders || ["anthropic", "gemini", "openai", "groq"];
10401
+ let apiKey;
10402
+ let model;
10403
+ if (dashCompModels?.model) {
10404
+ model = dashCompModels.model;
10405
+ const modelProvider = model.split("/")[0];
10406
+ if (modelProvider === "anthropic") apiKey = anthropicApiKey;
10407
+ else if (modelProvider === "gemini") apiKey = geminiApiKey;
10408
+ else if (modelProvider === "openai") apiKey = openaiApiKey;
10409
+ else if (modelProvider === "groq") apiKey = groqApiKey;
10410
+ } else {
10411
+ for (const provider of providers) {
10412
+ if (provider === "anthropic" && anthropicApiKey) {
10413
+ apiKey = anthropicApiKey;
10414
+ model = DEFAULT_DASH_COMP_MODELS.anthropic;
10415
+ break;
10416
+ } else if (provider === "gemini" && geminiApiKey) {
10417
+ apiKey = geminiApiKey;
10418
+ model = DEFAULT_DASH_COMP_MODELS.gemini;
10419
+ break;
10420
+ } else if (provider === "openai" && openaiApiKey) {
10421
+ apiKey = openaiApiKey;
10422
+ model = DEFAULT_DASH_COMP_MODELS.openai;
10423
+ break;
10424
+ } else if (provider === "groq" && groqApiKey) {
10425
+ apiKey = groqApiKey;
10426
+ model = DEFAULT_DASH_COMP_MODELS.groq;
10427
+ break;
10428
+ }
10429
+ }
10430
+ }
10431
+ return { apiKey, model };
10432
+ }
10433
+ function formatComponentsForPrompt(components) {
10434
+ if (!components || components.length === 0) {
10435
+ return "No components available";
10436
+ }
10437
+ return components.map((comp, idx) => {
10438
+ const keywords = comp.keywords ? comp.keywords.join(", ") : "";
10439
+ const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
10440
+ return `${idx + 1}. ID: ${comp.id}
10236
10441
  Name: ${comp.name}
10237
10442
  Type: ${comp.type}
10238
10443
  Description: ${comp.description || "No description"}
10239
10444
  Keywords: ${keywords}
10240
10445
  Props Structure: ${propsPreview}`;
10241
- }).join("\n\n");
10446
+ }).join("\n\n");
10447
+ }
10448
+ function formatToolsForPrompt(tools) {
10449
+ if (!tools || tools.length === 0) {
10450
+ return "No external tools available.";
10242
10451
  }
10243
- let availableToolsText = "No external tools available.";
10244
- if (tools && tools.length > 0) {
10245
- availableToolsText = tools.map((tool, idx) => {
10246
- const paramsStr = Object.entries(tool.params || {}).map(([key, type]) => `${key}: ${type}`).join(", ");
10247
- return `${idx + 1}. ID: ${tool.id}
10452
+ return tools.map((tool, idx) => {
10453
+ const paramsStr = Object.entries(tool.params || {}).map(([key, type]) => `${key}: ${type}`).join(", ");
10454
+ return `${idx + 1}. ID: ${tool.id}
10248
10455
  Name: ${tool.name}
10249
10456
  Description: ${tool.description}
10250
10457
  Parameters: { ${paramsStr} }`;
10251
- }).join("\n\n");
10458
+ }).join("\n\n");
10459
+ }
10460
+ function formatExistingComponentsForPrompt(existingComponents) {
10461
+ if (!existingComponents || existingComponents.length === 0) {
10462
+ return "No existing components in dashboard";
10252
10463
  }
10464
+ return JSON.stringify(existingComponents, null, 2);
10465
+ }
10466
+ function sendDashCompResponse(id, res, sendMessage, clientId) {
10467
+ const response = {
10468
+ id,
10469
+ type: "DASH_COMP_RES",
10470
+ from: { type: "data-agent" },
10471
+ to: {
10472
+ type: "runtime",
10473
+ id: clientId
10474
+ },
10475
+ payload: {
10476
+ ...res
10477
+ }
10478
+ };
10479
+ sendMessage(response);
10480
+ }
10481
+
10482
+ // src/dashComp/pick-component.ts
10483
+ init_logger();
10484
+ init_prompt_loader();
10485
+ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, _collections, tools, dashCompModels) {
10486
+ const errors = [];
10487
+ const availableComponentsText = formatComponentsForPrompt(components);
10488
+ const availableToolsText = formatToolsForPrompt(tools);
10253
10489
  try {
10254
10490
  const schemaDoc = schema.generateSchemaDocumentation();
10255
10491
  const databaseRules = await promptLoader.loadDatabaseRules();
@@ -10261,38 +10497,14 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10261
10497
  AVAILABLE_TOOLS: availableToolsText
10262
10498
  });
10263
10499
  logger.debug("[DASH_COMP_REQ] Loaded dash-comp-picker prompts with schema and tools");
10264
- const providers = llmProviders || ["anthropic", "gemini", "openai", "groq"];
10265
- let apiKey;
10266
- let model;
10267
- if (dashCompModels?.model) {
10268
- model = dashCompModels.model;
10269
- const modelProvider = model.split("/")[0];
10270
- if (modelProvider === "anthropic") apiKey = anthropicApiKey;
10271
- else if (modelProvider === "gemini") apiKey = geminiApiKey;
10272
- else if (modelProvider === "openai") apiKey = openaiApiKey;
10273
- else if (modelProvider === "groq") apiKey = groqApiKey;
10274
- logger.info(`[DASH_COMP_REQ] Using configured model: ${model}`);
10275
- } else {
10276
- for (const provider of providers) {
10277
- if (provider === "anthropic" && anthropicApiKey) {
10278
- apiKey = anthropicApiKey;
10279
- model = DEFAULT_DASH_COMP_MODELS.anthropic;
10280
- break;
10281
- } else if (provider === "gemini" && geminiApiKey) {
10282
- apiKey = geminiApiKey;
10283
- model = DEFAULT_DASH_COMP_MODELS.gemini;
10284
- break;
10285
- } else if (provider === "openai" && openaiApiKey) {
10286
- apiKey = openaiApiKey;
10287
- model = DEFAULT_DASH_COMP_MODELS.openai;
10288
- break;
10289
- } else if (provider === "groq" && groqApiKey) {
10290
- apiKey = groqApiKey;
10291
- model = DEFAULT_DASH_COMP_MODELS.groq;
10292
- break;
10293
- }
10294
- }
10295
- }
10500
+ const { apiKey, model } = getApiKeyAndModel(
10501
+ anthropicApiKey,
10502
+ groqApiKey,
10503
+ geminiApiKey,
10504
+ openaiApiKey,
10505
+ llmProviders,
10506
+ dashCompModels
10507
+ );
10296
10508
  if (!apiKey || !model) {
10297
10509
  errors.push("No API key available for any LLM provider");
10298
10510
  return { success: false, errors };
@@ -10352,7 +10564,8 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10352
10564
  data: {
10353
10565
  component: finalComponent,
10354
10566
  reasoning: result.reasoning || "Component selected based on user prompt",
10355
- dataSource: result.props.query ? "database" : result.props.externalTool ? "external_tool" : "none"
10567
+ dataSource: result.props.query ? "database" : result.props.externalTool ? "external_tool" : "none",
10568
+ isUpdate: result.isUpdate || false
10356
10569
  },
10357
10570
  errors: []
10358
10571
  };
@@ -10368,6 +10581,84 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10368
10581
  return { success: false, errors };
10369
10582
  }
10370
10583
  }
10584
+
10585
+ // src/dashComp/create-filter.ts
10586
+ init_logger();
10587
+ init_prompt_loader();
10588
+ async function createFilterWithLLM(prompt, components, existingComponents, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, tools, dashCompModels) {
10589
+ const errors = [];
10590
+ try {
10591
+ const filterComponents = components.filter((c) => c.type.startsWith("Filter"));
10592
+ if (filterComponents.length === 0) {
10593
+ errors.push("No filter components available");
10594
+ return { success: false, errors };
10595
+ }
10596
+ logger.debug(`[DASH_COMP_REQ:FILTER] Found ${filterComponents.length} filter components`);
10597
+ const schemaDoc = schema.generateSchemaDocumentation();
10598
+ const databaseRules = await promptLoader.loadDatabaseRules();
10599
+ const prompts = await promptLoader.loadPrompts("dash-filter-picker", {
10600
+ USER_PROMPT: prompt,
10601
+ AVAILABLE_COMPONENTS: formatComponentsForPrompt(filterComponents),
10602
+ EXISTING_COMPONENTS: formatExistingComponentsForPrompt(existingComponents),
10603
+ SCHEMA_DOC: schemaDoc || "No database schema available",
10604
+ DATABASE_RULES: databaseRules,
10605
+ AVAILABLE_TOOLS: formatToolsForPrompt(tools)
10606
+ });
10607
+ logger.debug("[DASH_COMP_REQ:FILTER] Loaded dash-filter-picker prompts");
10608
+ const { apiKey, model } = getApiKeyAndModel(
10609
+ anthropicApiKey,
10610
+ groqApiKey,
10611
+ geminiApiKey,
10612
+ openaiApiKey,
10613
+ llmProviders,
10614
+ dashCompModels
10615
+ );
10616
+ if (!apiKey || !model) {
10617
+ errors.push("No API key available for any LLM provider");
10618
+ return { success: false, errors };
10619
+ }
10620
+ logger.info(`[DASH_COMP_REQ:FILTER] Using model: ${model}`);
10621
+ const result = await LLM.stream(
10622
+ { sys: prompts.system, user: prompts.user },
10623
+ { model, maxTokens: 16384, temperature: 0.2, apiKey },
10624
+ true
10625
+ );
10626
+ logger.debug("[DASH_COMP_REQ:FILTER] LLM response received");
10627
+ logger.file("[DASH_COMP_REQ:FILTER] LLM response:", JSON.stringify(result, null, 2));
10628
+ if (!result.filterComponent) {
10629
+ errors.push("Invalid LLM response: missing filterComponent");
10630
+ userPromptErrorLogger.logError("DASH_COMP_REQ:FILTER", "Invalid LLM response structure", {
10631
+ prompt,
10632
+ result,
10633
+ missingFields: { filterComponent: !result.filterComponent }
10634
+ });
10635
+ return { success: false, errors };
10636
+ }
10637
+ logger.info(`[DASH_COMP_REQ:FILTER] Successfully created filter: ${result.filterComponent.componentType}`);
10638
+ logger.info(`[DASH_COMP_REQ:FILTER] Updated ${result.updatedComponents?.length || 0} components`);
10639
+ return {
10640
+ success: true,
10641
+ data: {
10642
+ filterComponent: result.filterComponent,
10643
+ updatedComponents: result.updatedComponents || [],
10644
+ filterBindings: result.filterBindings || {},
10645
+ reasoning: result.reasoning || "Filter created based on user prompt"
10646
+ },
10647
+ errors: []
10648
+ };
10649
+ } catch (error) {
10650
+ const errorMsg = error instanceof Error ? error.message : String(error);
10651
+ logger.error(`[DASH_COMP_REQ:FILTER] Error creating filter: ${errorMsg}`);
10652
+ userPromptErrorLogger.logError("DASH_COMP_REQ:FILTER", error instanceof Error ? error : new Error(errorMsg), {
10653
+ prompt,
10654
+ existingComponentsCount: existingComponents.length
10655
+ });
10656
+ errors.push(errorMsg);
10657
+ return { success: false, errors };
10658
+ }
10659
+ }
10660
+
10661
+ // src/dashComp/index.ts
10371
10662
  var processDashCompRequest = async (data, components, _sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools, dashCompModels) => {
10372
10663
  const errors = [];
10373
10664
  logger.debug("[DASH_COMP_REQ] Parsing incoming message data");
@@ -10382,17 +10673,25 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10382
10673
  const dashCompRequest = parseResult.data;
10383
10674
  const { id, payload } = dashCompRequest;
10384
10675
  const prompt = payload.prompt;
10676
+ const reqType = payload.req_type || "create";
10677
+ const existingComponents = payload.existingComponents || [];
10385
10678
  const wsId = dashCompRequest.from.id || "unknown";
10386
- const promptContext = `DASH_COMP: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
10679
+ const promptContext = `DASH_COMP[${reqType}]: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
10387
10680
  llmUsageLogger.resetLogFile(promptContext);
10388
10681
  if (!prompt) {
10389
10682
  errors.push("Prompt is required");
10390
10683
  }
10684
+ if (reqType === "filter" && existingComponents.length === 0) {
10685
+ errors.push("Filter request requires existingComponents");
10686
+ }
10391
10687
  if (errors.length > 0) {
10392
10688
  return { success: false, errors, id, wsId };
10393
10689
  }
10394
- logger.info(`[DASH_COMP_REQ] Processing request for prompt: "${prompt.substring(0, 50)}..."`);
10690
+ logger.info(`[DASH_COMP_REQ] Processing ${reqType} request for prompt: "${prompt.substring(0, 50)}..."`);
10395
10691
  logger.info(`[DASH_COMP_REQ] Available: ${components?.length || 0} components, ${tools?.length || 0} tools`);
10692
+ if (existingComponents.length > 0) {
10693
+ logger.info(`[DASH_COMP_REQ] Existing components in dashboard: ${existingComponents.length}`);
10694
+ }
10396
10695
  if (!components || components.length === 0) {
10397
10696
  logger.warn("[DASH_COMP_REQ] No components available");
10398
10697
  return {
@@ -10402,19 +10701,35 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10402
10701
  wsId
10403
10702
  };
10404
10703
  }
10405
- const llmResponse = await pickComponentWithLLM(
10406
- prompt,
10407
- components,
10408
- anthropicApiKey,
10409
- groqApiKey,
10410
- geminiApiKey,
10411
- openaiApiKey,
10412
- llmProviders,
10413
- collections,
10414
- tools,
10415
- dashCompModels
10416
- );
10417
- llmUsageLogger.logSessionSummary(`DASH_COMP: ${prompt?.substring(0, 30)}`);
10704
+ let llmResponse;
10705
+ if (reqType === "filter") {
10706
+ llmResponse = await createFilterWithLLM(
10707
+ prompt,
10708
+ components,
10709
+ existingComponents,
10710
+ anthropicApiKey,
10711
+ groqApiKey,
10712
+ geminiApiKey,
10713
+ openaiApiKey,
10714
+ llmProviders,
10715
+ tools,
10716
+ dashCompModels
10717
+ );
10718
+ } else {
10719
+ llmResponse = await pickComponentWithLLM(
10720
+ prompt,
10721
+ components,
10722
+ anthropicApiKey,
10723
+ groqApiKey,
10724
+ geminiApiKey,
10725
+ openaiApiKey,
10726
+ llmProviders,
10727
+ collections,
10728
+ tools,
10729
+ dashCompModels
10730
+ );
10731
+ }
10732
+ llmUsageLogger.logSessionSummary(`DASH_COMP[${reqType}]: ${prompt?.substring(0, 30)}`);
10418
10733
  return {
10419
10734
  success: llmResponse.success,
10420
10735
  data: llmResponse.data,
@@ -10447,22 +10762,7 @@ async function handleDashCompRequest(data, components, sendMessage, anthropicApi
10447
10762
  sendMessage,
10448
10763
  response.wsId || data.from?.id
10449
10764
  );
10450
- }
10451
- function sendDashCompResponse(id, res, sendMessage, clientId) {
10452
- const response = {
10453
- id,
10454
- type: "DASH_COMP_RES",
10455
- from: { type: "data-agent" },
10456
- to: {
10457
- type: "runtime",
10458
- id: clientId
10459
- },
10460
- payload: {
10461
- ...res
10462
- }
10463
- };
10464
- sendMessage(response);
10465
- logger.info(`[DASH_COMP_REQ] Response sent to client ${clientId}`);
10765
+ logger.info(`[DASH_COMP_REQ] Response sent to client ${response.wsId || data.from?.id}`);
10466
10766
  }
10467
10767
 
10468
10768
  // src/auth/user-manager.ts
@@ -11310,7 +11610,6 @@ var SuperatomSDK = class {
11310
11610
  }
11311
11611
  this.apiKey = config.apiKey;
11312
11612
  this.projectId = config.projectId;
11313
- this.userId = config.userId || "anonymous";
11314
11613
  this.type = config.type || "data-agent";
11315
11614
  this.bundleDir = config.bundleDir;
11316
11615
  this.url = config.url || process.env.SA_WEBSOCKET_URL || DEFAULT_WS_URL;
@@ -11412,7 +11711,6 @@ var SuperatomSDK = class {
11412
11711
  url.searchParams.set("apiKey", this.apiKey);
11413
11712
  }
11414
11713
  url.searchParams.set("projectId", this.projectId);
11415
- url.searchParams.set("userId", this.userId);
11416
11714
  url.searchParams.set("type", this.type);
11417
11715
  logger.info(`Connecting to WebSocket: ${url.toString()}`);
11418
11716
  this.ws = createWebSocket(url.toString());
@@ -11473,7 +11771,7 @@ var SuperatomSDK = class {
11473
11771
  });
11474
11772
  break;
11475
11773
  case "USER_PROMPT_REQ":
11476
- 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) => {
11774
+ handleUserPromptRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.geminiApiKey, this.openaiApiKey, this.llmProviders, this.collections, this.tools).catch((error) => {
11477
11775
  logger.error("Failed to handle user prompt request:", error);
11478
11776
  });
11479
11777
  break;
@@ -11483,7 +11781,7 @@ var SuperatomSDK = class {
11483
11781
  });
11484
11782
  break;
11485
11783
  case "USER_PROMPT_SUGGESTIONS_REQ":
11486
- handleUserPromptSuggestions(parsed, this.components, (msg) => this.send(msg), this.collections, this.userId).catch((error) => {
11784
+ handleUserPromptSuggestions(parsed, this.components, (msg) => this.send(msg), this.collections).catch((error) => {
11487
11785
  logger.error("Failed to handle user prompt suggestions request:", error);
11488
11786
  });
11489
11787
  break;