@superatomai/sdk-node 0.0.42 → 0.0.44

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,142 @@ 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
1178
+ 2. **Update existing components** with dynamic title/description interpolation if needed
1179
+ 3. **Preserve all existing props** - the filter system handles param merging at runtime
1180
+
1181
+ ## How The Filter System Works
1182
+
1183
+ 1. Filter component has a \`filters\` array with preset options, each containing \`label\`, \`value\`, and \`params\`
1184
+ 2. When user selects a filter option, those \`params\` are broadcast to all listening components
1185
+ 3. Components automatically merge filter params with their existing params (filter values override defaults)
1186
+ 4. Component titles/descriptions can use \`{%filterKeyLabel%}\` syntax for dynamic text
1187
+
1188
+ ## Filter Component Structure
1189
+
1190
+ The filter uses DynamicFilterDropdown with:
1191
+ - **filterKey**: Identifier for label interpolation (e.g., "period", "name", "category")
1192
+ - **filters**: Array of options with label, value, params, and optionally isDefault
1193
+ - **defaultValue**: The value of the initially selected option
1194
+
1195
+ ## Dynamic Title/Description Interpolation
1196
+
1197
+ Use \`{%filterKeyLabel%}\` syntax for dynamic text:
1198
+ - filterKey "period" \u2192 use \`{%periodLabel%}\` in titles/descriptions
1199
+ - filterKey "name" \u2192 use \`{%nameLabel%}\` in titles/descriptions
1200
+ - Example: \`"{%periodLabel%} Revenue"\` becomes "Q3 2025 Revenue" when user selects "Q3 2025"
1201
+
1202
+ **CRITICAL Template Syntax:**
1203
+ - Use \`{%keyLabel%}\` format (percent signs, key + "Label" suffix)
1204
+ - Do NOT use \`{{...}}\` or \`$...\` syntax - these don't work
1205
+
1206
+ ## Updating Existing Components
1207
+
1208
+ **IMPORTANT - Parameter Handling:**
1209
+ - Do NOT change existing parameter values to placeholders
1210
+ - Keep all existing/default parameter values as they are
1211
+ - The filter system MERGES params at runtime: filter params override component defaults
1212
+
1213
+ **What to modify in existing components:**
1214
+ - Modify \`title\` for \`{%filterKeyLabel%}\` interpolation (only if title exists)
1215
+ - Modify \`description\` for interpolation (only if description exists)
1216
+ - Modify other props only if specifically needed for the filter to function
1217
+ - Copy ALL other props exactly as provided
1218
+
1219
+ ### Database Query Rules
1220
+ {{DATABASE_RULES}}
1221
+
1222
+ ## Output Format
1223
+
1224
+ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1225
+
1226
+ {
1227
+ "filterComponent": {
1228
+ "id": "filter-<descriptive-id>",
1229
+ "name": "DynamicFilterDropdown",
1230
+ "type": "FilterDropdown",
1231
+ "props": {
1232
+ "title": "<Filter display title>",
1233
+ "filterKey": "<key_for_interpolation>",
1234
+ "defaultValue": "<default_option_value>",
1235
+ "filters": [
1236
+ {
1237
+ "label": "<Display label for option>",
1238
+ "value": "<unique_option_value>",
1239
+ "params": { "<param_key>": "<actual_value>", "...": "..." },
1240
+ "isDefault": true
1241
+ }
1242
+ ]
1243
+ }
1244
+ },
1245
+ "updatedComponents": [
1246
+ {
1247
+ "id": "<existing_component_id>",
1248
+ "name": "<existing_component_name>",
1249
+ "type": "<existing_type>",
1250
+ "props": {
1251
+ "...all existing props preserved...",
1252
+ "title": "{%<filterKey>Label%} <rest of title>",
1253
+ "description": "<updated if needed>"
1254
+ }
1255
+ }
1256
+ ],
1257
+ "filterBindings": {
1258
+ "<param_key>": "Describes which filter param this binds to"
1259
+ },
1260
+ "reasoning": "Explanation of filter choice and what params it provides"
1261
+ }
1262
+
1263
+ **CRITICAL RULES:**
1264
+ 1. Return ONLY valid JSON (no markdown code blocks)
1265
+ 2. **COPY ALL existing props** - modify title/description for interpolation only if they exist
1266
+ 3. **DO NOT change parameter values** - keep existing defaults, filter merges at runtime
1267
+ 4. Use \`{%filterKeyLabel%}\` for dynamic text (NOT \`{{...}}\` or \`$...\`)
1268
+ 5. Filter \`params\` must have ACTUAL values (real dates, strings), not placeholders
1269
+ 6. Each filter option needs: label, value, params (and optionally isDefault)
1141
1270
 
1142
- ### Database Schema
1271
+ ## Database Schema
1143
1272
  {{SCHEMA_DOC}}
1144
1273
 
1145
- ### Available External Tools
1274
+ ## Available External Tools
1146
1275
  {{AVAILABLE_TOOLS}}
1147
1276
 
1148
- ### Available Components
1149
- {{AVAILABLE_COMPONENTS}}`,
1277
+ ## Available Filter Components
1278
+ {{AVAILABLE_COMPONENTS}}
1279
+
1280
+ ## Existing Dashboard Components
1281
+ {{EXISTING_COMPONENTS}}
1282
+
1283
+ ---
1284
+
1285
+ ## CONTEXT`,
1150
1286
  user: `{{USER_PROMPT}}`
1151
1287
  }
1152
1288
  };
@@ -1854,6 +1990,7 @@ var AuthVerifyRequestMessageSchema = z3.object({
1854
1990
  });
1855
1991
  var UserPromptRequestPayloadSchema = z3.object({
1856
1992
  prompt: z3.string(),
1993
+ userId: z3.string().optional(),
1857
1994
  SA_RUNTIME: z3.object({
1858
1995
  threadId: z3.string(),
1859
1996
  uiBlockId: z3.string()
@@ -1868,6 +2005,7 @@ var UserPromptRequestMessageSchema = z3.object({
1868
2005
  });
1869
2006
  var UserPromptSuggestionsPayloadSchema = z3.object({
1870
2007
  prompt: z3.string(),
2008
+ userId: z3.string().optional(),
1871
2009
  limit: z3.number().int().positive().default(5),
1872
2010
  similarityThreshold: z3.number().min(0).max(1).default(0.4)
1873
2011
  });
@@ -1957,6 +2095,7 @@ var UILogsMessageSchema = z3.object({
1957
2095
  payload: UILogsPayloadSchema
1958
2096
  });
1959
2097
  var ActionsRequestPayloadSchema = z3.object({
2098
+ userId: z3.string().optional(),
1960
2099
  SA_RUNTIME: z3.object({
1961
2100
  threadId: z3.string(),
1962
2101
  uiBlockId: z3.string()
@@ -2157,10 +2296,15 @@ var KbNodesRequestMessageSchema = z3.object({
2157
2296
  });
2158
2297
  var DashCompRequestPayloadSchema = z3.object({
2159
2298
  prompt: z3.string(),
2299
+ userId: z3.string().optional(),
2160
2300
  SA_RUNTIME: z3.object({
2161
2301
  threadId: z3.string().optional(),
2162
2302
  uiBlockId: z3.string().optional()
2163
- }).optional()
2303
+ }).optional(),
2304
+ /** Existing components in the dashboard (for update/filter operations) */
2305
+ existingComponents: z3.array(ComponentSchema).optional(),
2306
+ /** Request type: create (new component), update (modify existing), filter (create filter + update components) */
2307
+ req_type: z3.enum(["create", "update", "filter"]).optional()
2164
2308
  });
2165
2309
  var DashCompRequestMessageSchema = z3.object({
2166
2310
  id: z3.string(),
@@ -7303,7 +7447,7 @@ var CONTEXT_CONFIG = {
7303
7447
  };
7304
7448
 
7305
7449
  // src/handlers/user-prompt-request.ts
7306
- var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, userId) => {
7450
+ var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools) => {
7307
7451
  const errors = [];
7308
7452
  logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
7309
7453
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
@@ -7317,6 +7461,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7317
7461
  const userPromptRequest = parseResult.data;
7318
7462
  const { id, payload } = userPromptRequest;
7319
7463
  const prompt = payload.prompt;
7464
+ const userId = payload.userId;
7320
7465
  const SA_RUNTIME = payload.SA_RUNTIME;
7321
7466
  const wsId = userPromptRequest.from.id || "unknown";
7322
7467
  const promptContext = `User Prompt: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
@@ -7489,8 +7634,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7489
7634
  wsId
7490
7635
  };
7491
7636
  };
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);
7637
+ async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools) {
7638
+ const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools);
7494
7639
  sendDataResponse4(
7495
7640
  response.id || data.id,
7496
7641
  {
@@ -7522,11 +7667,11 @@ function sendDataResponse4(id, res, sendMessage, clientId) {
7522
7667
 
7523
7668
  // src/handlers/user-prompt-suggestions.ts
7524
7669
  init_logger();
7525
- async function handleUserPromptSuggestions(data, components, sendMessage, collections, userId) {
7670
+ async function handleUserPromptSuggestions(data, components, sendMessage, collections) {
7526
7671
  try {
7527
7672
  const request = UserPromptSuggestionsMessageSchema.parse(data);
7528
7673
  const { id, payload, from } = request;
7529
- const { prompt, limit = 10 } = payload;
7674
+ const { prompt, userId, limit = 10 } = payload;
7530
7675
  const wsId = from.id;
7531
7676
  logger.info(`[USER_PROMPT_SUGGESTIONS_REQ ${id}] Processing user prompt suggestions: ${prompt}`);
7532
7677
  if (!prompt || prompt.trim().length === 0) {
@@ -10166,40 +10311,108 @@ function sendResponse8(id, res, sendMessage, clientId) {
10166
10311
  sendMessage(response);
10167
10312
  }
10168
10313
 
10169
- // src/handlers/dash-comp-request.ts
10314
+ // src/dashComp/index.ts
10170
10315
  init_logger();
10171
- init_prompt_loader();
10316
+
10317
+ // src/dashComp/types.ts
10172
10318
  var DEFAULT_DASH_COMP_MODELS = {
10173
10319
  anthropic: "anthropic/claude-haiku-4-5-20251001",
10174
10320
  gemini: "gemini/gemini-3-flash-preview",
10175
10321
  openai: "openai/gpt-4o-mini",
10176
10322
  groq: "groq/llama-3.3-70b-versatile"
10177
10323
  };
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}
10324
+
10325
+ // src/dashComp/utils.ts
10326
+ function getApiKeyAndModel(anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, dashCompModels) {
10327
+ const providers = llmProviders || ["anthropic", "gemini", "openai", "groq"];
10328
+ let apiKey;
10329
+ let model;
10330
+ if (dashCompModels?.model) {
10331
+ model = dashCompModels.model;
10332
+ const modelProvider = model.split("/")[0];
10333
+ if (modelProvider === "anthropic") apiKey = anthropicApiKey;
10334
+ else if (modelProvider === "gemini") apiKey = geminiApiKey;
10335
+ else if (modelProvider === "openai") apiKey = openaiApiKey;
10336
+ else if (modelProvider === "groq") apiKey = groqApiKey;
10337
+ } else {
10338
+ for (const provider of providers) {
10339
+ if (provider === "anthropic" && anthropicApiKey) {
10340
+ apiKey = anthropicApiKey;
10341
+ model = DEFAULT_DASH_COMP_MODELS.anthropic;
10342
+ break;
10343
+ } else if (provider === "gemini" && geminiApiKey) {
10344
+ apiKey = geminiApiKey;
10345
+ model = DEFAULT_DASH_COMP_MODELS.gemini;
10346
+ break;
10347
+ } else if (provider === "openai" && openaiApiKey) {
10348
+ apiKey = openaiApiKey;
10349
+ model = DEFAULT_DASH_COMP_MODELS.openai;
10350
+ break;
10351
+ } else if (provider === "groq" && groqApiKey) {
10352
+ apiKey = groqApiKey;
10353
+ model = DEFAULT_DASH_COMP_MODELS.groq;
10354
+ break;
10355
+ }
10356
+ }
10357
+ }
10358
+ return { apiKey, model };
10359
+ }
10360
+ function formatComponentsForPrompt(components) {
10361
+ if (!components || components.length === 0) {
10362
+ return "No components available";
10363
+ }
10364
+ return components.map((comp, idx) => {
10365
+ const keywords = comp.keywords ? comp.keywords.join(", ") : "";
10366
+ const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
10367
+ return `${idx + 1}. ID: ${comp.id}
10186
10368
  Name: ${comp.name}
10187
10369
  Type: ${comp.type}
10188
10370
  Description: ${comp.description || "No description"}
10189
10371
  Keywords: ${keywords}
10190
10372
  Props Structure: ${propsPreview}`;
10191
- }).join("\n\n");
10373
+ }).join("\n\n");
10374
+ }
10375
+ function formatToolsForPrompt(tools) {
10376
+ if (!tools || tools.length === 0) {
10377
+ return "No external tools available.";
10192
10378
  }
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}
10379
+ return tools.map((tool, idx) => {
10380
+ const paramsStr = Object.entries(tool.params || {}).map(([key, type]) => `${key}: ${type}`).join(", ");
10381
+ return `${idx + 1}. ID: ${tool.id}
10198
10382
  Name: ${tool.name}
10199
10383
  Description: ${tool.description}
10200
10384
  Parameters: { ${paramsStr} }`;
10201
- }).join("\n\n");
10385
+ }).join("\n\n");
10386
+ }
10387
+ function formatExistingComponentsForPrompt(existingComponents) {
10388
+ if (!existingComponents || existingComponents.length === 0) {
10389
+ return "No existing components in dashboard";
10202
10390
  }
10391
+ return JSON.stringify(existingComponents, null, 2);
10392
+ }
10393
+ function sendDashCompResponse(id, res, sendMessage, clientId) {
10394
+ const response = {
10395
+ id,
10396
+ type: "DASH_COMP_RES",
10397
+ from: { type: "data-agent" },
10398
+ to: {
10399
+ type: "runtime",
10400
+ id: clientId
10401
+ },
10402
+ payload: {
10403
+ ...res
10404
+ }
10405
+ };
10406
+ sendMessage(response);
10407
+ }
10408
+
10409
+ // src/dashComp/pick-component.ts
10410
+ init_logger();
10411
+ init_prompt_loader();
10412
+ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, _collections, tools, dashCompModels) {
10413
+ const errors = [];
10414
+ const availableComponentsText = formatComponentsForPrompt(components);
10415
+ const availableToolsText = formatToolsForPrompt(tools);
10203
10416
  try {
10204
10417
  const schemaDoc = schema.generateSchemaDocumentation();
10205
10418
  const databaseRules = await promptLoader.loadDatabaseRules();
@@ -10211,38 +10424,14 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10211
10424
  AVAILABLE_TOOLS: availableToolsText
10212
10425
  });
10213
10426
  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
- }
10427
+ const { apiKey, model } = getApiKeyAndModel(
10428
+ anthropicApiKey,
10429
+ groqApiKey,
10430
+ geminiApiKey,
10431
+ openaiApiKey,
10432
+ llmProviders,
10433
+ dashCompModels
10434
+ );
10246
10435
  if (!apiKey || !model) {
10247
10436
  errors.push("No API key available for any LLM provider");
10248
10437
  return { success: false, errors };
@@ -10273,13 +10462,13 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10273
10462
  });
10274
10463
  return { success: false, errors };
10275
10464
  }
10276
- const originalComponent = components.find((c) => c.id === result.componentId);
10465
+ const originalComponent = components.find((c) => c.name === result.componentName);
10277
10466
  if (!originalComponent) {
10278
- errors.push(`Component ${result.componentId} not found in available components`);
10467
+ errors.push(`Component ${result.componentName} not found in available components`);
10279
10468
  userPromptErrorLogger.logError("DASH_COMP_REQ", "Component not found", {
10280
10469
  prompt,
10281
- componentId: result.componentId,
10282
- availableComponentIds: components.map((c) => c.id)
10470
+ componentName: result.componentName,
10471
+ availableComponentNames: components.map((c) => c.name)
10283
10472
  });
10284
10473
  return { success: false, errors };
10285
10474
  }
@@ -10302,7 +10491,8 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10302
10491
  data: {
10303
10492
  component: finalComponent,
10304
10493
  reasoning: result.reasoning || "Component selected based on user prompt",
10305
- dataSource: result.props.query ? "database" : result.props.externalTool ? "external_tool" : "none"
10494
+ dataSource: result.props.query ? "database" : result.props.externalTool ? "external_tool" : "none",
10495
+ isUpdate: result.isUpdate || false
10306
10496
  },
10307
10497
  errors: []
10308
10498
  };
@@ -10318,6 +10508,84 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10318
10508
  return { success: false, errors };
10319
10509
  }
10320
10510
  }
10511
+
10512
+ // src/dashComp/create-filter.ts
10513
+ init_logger();
10514
+ init_prompt_loader();
10515
+ async function createFilterWithLLM(prompt, components, existingComponents, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, tools, dashCompModels) {
10516
+ const errors = [];
10517
+ try {
10518
+ const filterComponents = components.filter((c) => c.type.startsWith("Filter"));
10519
+ if (filterComponents.length === 0) {
10520
+ errors.push("No filter components available");
10521
+ return { success: false, errors };
10522
+ }
10523
+ logger.debug(`[DASH_COMP_REQ:FILTER] Found ${filterComponents.length} filter components`);
10524
+ const schemaDoc = schema.generateSchemaDocumentation();
10525
+ const databaseRules = await promptLoader.loadDatabaseRules();
10526
+ const prompts = await promptLoader.loadPrompts("dash-filter-picker", {
10527
+ USER_PROMPT: prompt,
10528
+ AVAILABLE_COMPONENTS: formatComponentsForPrompt(filterComponents),
10529
+ EXISTING_COMPONENTS: formatExistingComponentsForPrompt(existingComponents),
10530
+ SCHEMA_DOC: schemaDoc || "No database schema available",
10531
+ DATABASE_RULES: databaseRules,
10532
+ AVAILABLE_TOOLS: formatToolsForPrompt(tools)
10533
+ });
10534
+ logger.debug("[DASH_COMP_REQ:FILTER] Loaded dash-filter-picker prompts");
10535
+ const { apiKey, model } = getApiKeyAndModel(
10536
+ anthropicApiKey,
10537
+ groqApiKey,
10538
+ geminiApiKey,
10539
+ openaiApiKey,
10540
+ llmProviders,
10541
+ dashCompModels
10542
+ );
10543
+ if (!apiKey || !model) {
10544
+ errors.push("No API key available for any LLM provider");
10545
+ return { success: false, errors };
10546
+ }
10547
+ logger.info(`[DASH_COMP_REQ:FILTER] Using model: ${model}`);
10548
+ const result = await LLM.stream(
10549
+ { sys: prompts.system, user: prompts.user },
10550
+ { model, maxTokens: 16384, temperature: 0.2, apiKey },
10551
+ true
10552
+ );
10553
+ logger.debug("[DASH_COMP_REQ:FILTER] LLM response received");
10554
+ logger.file("[DASH_COMP_REQ:FILTER] LLM response:", JSON.stringify(result, null, 2));
10555
+ if (!result.filterComponent) {
10556
+ errors.push("Invalid LLM response: missing filterComponent");
10557
+ userPromptErrorLogger.logError("DASH_COMP_REQ:FILTER", "Invalid LLM response structure", {
10558
+ prompt,
10559
+ result,
10560
+ missingFields: { filterComponent: !result.filterComponent }
10561
+ });
10562
+ return { success: false, errors };
10563
+ }
10564
+ logger.info(`[DASH_COMP_REQ:FILTER] Successfully created filter: ${result.filterComponent.componentType}`);
10565
+ logger.info(`[DASH_COMP_REQ:FILTER] Updated ${result.updatedComponents?.length || 0} components`);
10566
+ return {
10567
+ success: true,
10568
+ data: {
10569
+ filterComponent: result.filterComponent,
10570
+ updatedComponents: result.updatedComponents || [],
10571
+ filterBindings: result.filterBindings || {},
10572
+ reasoning: result.reasoning || "Filter created based on user prompt"
10573
+ },
10574
+ errors: []
10575
+ };
10576
+ } catch (error) {
10577
+ const errorMsg = error instanceof Error ? error.message : String(error);
10578
+ logger.error(`[DASH_COMP_REQ:FILTER] Error creating filter: ${errorMsg}`);
10579
+ userPromptErrorLogger.logError("DASH_COMP_REQ:FILTER", error instanceof Error ? error : new Error(errorMsg), {
10580
+ prompt,
10581
+ existingComponentsCount: existingComponents.length
10582
+ });
10583
+ errors.push(errorMsg);
10584
+ return { success: false, errors };
10585
+ }
10586
+ }
10587
+
10588
+ // src/dashComp/index.ts
10321
10589
  var processDashCompRequest = async (data, components, _sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools, dashCompModels) => {
10322
10590
  const errors = [];
10323
10591
  logger.debug("[DASH_COMP_REQ] Parsing incoming message data");
@@ -10332,17 +10600,25 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10332
10600
  const dashCompRequest = parseResult.data;
10333
10601
  const { id, payload } = dashCompRequest;
10334
10602
  const prompt = payload.prompt;
10603
+ const reqType = payload.req_type || "create";
10604
+ const existingComponents = payload.existingComponents || [];
10335
10605
  const wsId = dashCompRequest.from.id || "unknown";
10336
- const promptContext = `DASH_COMP: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
10606
+ const promptContext = `DASH_COMP[${reqType}]: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
10337
10607
  llmUsageLogger.resetLogFile(promptContext);
10338
10608
  if (!prompt) {
10339
10609
  errors.push("Prompt is required");
10340
10610
  }
10611
+ if (reqType === "filter" && existingComponents.length === 0) {
10612
+ errors.push("Filter request requires existingComponents");
10613
+ }
10341
10614
  if (errors.length > 0) {
10342
10615
  return { success: false, errors, id, wsId };
10343
10616
  }
10344
- logger.info(`[DASH_COMP_REQ] Processing request for prompt: "${prompt.substring(0, 50)}..."`);
10617
+ logger.info(`[DASH_COMP_REQ] Processing ${reqType} request for prompt: "${prompt.substring(0, 50)}..."`);
10345
10618
  logger.info(`[DASH_COMP_REQ] Available: ${components?.length || 0} components, ${tools?.length || 0} tools`);
10619
+ if (existingComponents.length > 0) {
10620
+ logger.info(`[DASH_COMP_REQ] Existing components in dashboard: ${existingComponents.length}`);
10621
+ }
10346
10622
  if (!components || components.length === 0) {
10347
10623
  logger.warn("[DASH_COMP_REQ] No components available");
10348
10624
  return {
@@ -10352,19 +10628,35 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10352
10628
  wsId
10353
10629
  };
10354
10630
  }
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)}`);
10631
+ let llmResponse;
10632
+ if (reqType === "filter") {
10633
+ llmResponse = await createFilterWithLLM(
10634
+ prompt,
10635
+ components,
10636
+ existingComponents,
10637
+ anthropicApiKey,
10638
+ groqApiKey,
10639
+ geminiApiKey,
10640
+ openaiApiKey,
10641
+ llmProviders,
10642
+ tools,
10643
+ dashCompModels
10644
+ );
10645
+ } else {
10646
+ llmResponse = await pickComponentWithLLM(
10647
+ prompt,
10648
+ components,
10649
+ anthropicApiKey,
10650
+ groqApiKey,
10651
+ geminiApiKey,
10652
+ openaiApiKey,
10653
+ llmProviders,
10654
+ collections,
10655
+ tools,
10656
+ dashCompModels
10657
+ );
10658
+ }
10659
+ llmUsageLogger.logSessionSummary(`DASH_COMP[${reqType}]: ${prompt?.substring(0, 30)}`);
10368
10660
  return {
10369
10661
  success: llmResponse.success,
10370
10662
  data: llmResponse.data,
@@ -10397,22 +10689,7 @@ async function handleDashCompRequest(data, components, sendMessage, anthropicApi
10397
10689
  sendMessage,
10398
10690
  response.wsId || data.from?.id
10399
10691
  );
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}`);
10692
+ logger.info(`[DASH_COMP_REQ] Response sent to client ${response.wsId || data.from?.id}`);
10416
10693
  }
10417
10694
 
10418
10695
  // src/auth/user-manager.ts
@@ -11260,7 +11537,6 @@ var SuperatomSDK = class {
11260
11537
  }
11261
11538
  this.apiKey = config.apiKey;
11262
11539
  this.projectId = config.projectId;
11263
- this.userId = config.userId || "anonymous";
11264
11540
  this.type = config.type || "data-agent";
11265
11541
  this.bundleDir = config.bundleDir;
11266
11542
  this.url = config.url || process.env.SA_WEBSOCKET_URL || DEFAULT_WS_URL;
@@ -11362,7 +11638,6 @@ var SuperatomSDK = class {
11362
11638
  url.searchParams.set("apiKey", this.apiKey);
11363
11639
  }
11364
11640
  url.searchParams.set("projectId", this.projectId);
11365
- url.searchParams.set("userId", this.userId);
11366
11641
  url.searchParams.set("type", this.type);
11367
11642
  logger.info(`Connecting to WebSocket: ${url.toString()}`);
11368
11643
  this.ws = createWebSocket(url.toString());
@@ -11423,7 +11698,7 @@ var SuperatomSDK = class {
11423
11698
  });
11424
11699
  break;
11425
11700
  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) => {
11701
+ 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
11702
  logger.error("Failed to handle user prompt request:", error);
11428
11703
  });
11429
11704
  break;
@@ -11433,7 +11708,7 @@ var SuperatomSDK = class {
11433
11708
  });
11434
11709
  break;
11435
11710
  case "USER_PROMPT_SUGGESTIONS_REQ":
11436
- handleUserPromptSuggestions(parsed, this.components, (msg) => this.send(msg), this.collections, this.userId).catch((error) => {
11711
+ handleUserPromptSuggestions(parsed, this.components, (msg) => this.send(msg), this.collections).catch((error) => {
11437
11712
  logger.error("Failed to handle user prompt suggestions request:", error);
11438
11713
  });
11439
11714
  break;