@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.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,142 @@ 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
1200
+ 2. **Update existing components** with dynamic title/description interpolation if needed
1201
+ 3. **Preserve all existing props** - the filter system handles param merging at runtime
1202
+
1203
+ ## How The Filter System Works
1204
+
1205
+ 1. Filter component has a \`filters\` array with preset options, each containing \`label\`, \`value\`, and \`params\`
1206
+ 2. When user selects a filter option, those \`params\` are broadcast to all listening components
1207
+ 3. Components automatically merge filter params with their existing params (filter values override defaults)
1208
+ 4. Component titles/descriptions can use \`{%filterKeyLabel%}\` syntax for dynamic text
1209
+
1210
+ ## Filter Component Structure
1211
+
1212
+ The filter uses DynamicFilterDropdown with:
1213
+ - **filterKey**: Identifier for label interpolation (e.g., "period", "name", "category")
1214
+ - **filters**: Array of options with label, value, params, and optionally isDefault
1215
+ - **defaultValue**: The value of the initially selected option
1216
+
1217
+ ## Dynamic Title/Description Interpolation
1218
+
1219
+ Use \`{%filterKeyLabel%}\` syntax for dynamic text:
1220
+ - filterKey "period" \u2192 use \`{%periodLabel%}\` in titles/descriptions
1221
+ - filterKey "name" \u2192 use \`{%nameLabel%}\` in titles/descriptions
1222
+ - Example: \`"{%periodLabel%} Revenue"\` becomes "Q3 2025 Revenue" when user selects "Q3 2025"
1223
+
1224
+ **CRITICAL Template Syntax:**
1225
+ - Use \`{%keyLabel%}\` format (percent signs, key + "Label" suffix)
1226
+ - Do NOT use \`{{...}}\` or \`$...\` syntax - these don't work
1227
+
1228
+ ## Updating Existing Components
1229
+
1230
+ **IMPORTANT - Parameter Handling:**
1231
+ - Do NOT change existing parameter values to placeholders
1232
+ - Keep all existing/default parameter values as they are
1233
+ - The filter system MERGES params at runtime: filter params override component defaults
1234
+
1235
+ **What to modify in existing components:**
1236
+ - Modify \`title\` for \`{%filterKeyLabel%}\` interpolation (only if title exists)
1237
+ - Modify \`description\` for interpolation (only if description exists)
1238
+ - Modify other props only if specifically needed for the filter to function
1239
+ - Copy ALL other props exactly as provided
1240
+
1241
+ ### Database Query Rules
1242
+ {{DATABASE_RULES}}
1243
+
1244
+ ## Output Format
1245
+
1246
+ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
1247
+
1248
+ {
1249
+ "filterComponent": {
1250
+ "id": "filter-<descriptive-id>",
1251
+ "name": "DynamicFilterDropdown",
1252
+ "type": "FilterDropdown",
1253
+ "props": {
1254
+ "title": "<Filter display title>",
1255
+ "filterKey": "<key_for_interpolation>",
1256
+ "defaultValue": "<default_option_value>",
1257
+ "filters": [
1258
+ {
1259
+ "label": "<Display label for option>",
1260
+ "value": "<unique_option_value>",
1261
+ "params": { "<param_key>": "<actual_value>", "...": "..." },
1262
+ "isDefault": true
1263
+ }
1264
+ ]
1265
+ }
1266
+ },
1267
+ "updatedComponents": [
1268
+ {
1269
+ "id": "<existing_component_id>",
1270
+ "name": "<existing_component_name>",
1271
+ "type": "<existing_type>",
1272
+ "props": {
1273
+ "...all existing props preserved...",
1274
+ "title": "{%<filterKey>Label%} <rest of title>",
1275
+ "description": "<updated if needed>"
1276
+ }
1277
+ }
1278
+ ],
1279
+ "filterBindings": {
1280
+ "<param_key>": "Describes which filter param this binds to"
1281
+ },
1282
+ "reasoning": "Explanation of filter choice and what params it provides"
1283
+ }
1284
+
1285
+ **CRITICAL RULES:**
1286
+ 1. Return ONLY valid JSON (no markdown code blocks)
1287
+ 2. **COPY ALL existing props** - modify title/description for interpolation only if they exist
1288
+ 3. **DO NOT change parameter values** - keep existing defaults, filter merges at runtime
1289
+ 4. Use \`{%filterKeyLabel%}\` for dynamic text (NOT \`{{...}}\` or \`$...\`)
1290
+ 5. Filter \`params\` must have ACTUAL values (real dates, strings), not placeholders
1291
+ 6. Each filter option needs: label, value, params (and optionally isDefault)
1163
1292
 
1164
- ### Database Schema
1293
+ ## Database Schema
1165
1294
  {{SCHEMA_DOC}}
1166
1295
 
1167
- ### Available External Tools
1296
+ ## Available External Tools
1168
1297
  {{AVAILABLE_TOOLS}}
1169
1298
 
1170
- ### Available Components
1171
- {{AVAILABLE_COMPONENTS}}`,
1299
+ ## Available Filter Components
1300
+ {{AVAILABLE_COMPONENTS}}
1301
+
1302
+ ## Existing Dashboard Components
1303
+ {{EXISTING_COMPONENTS}}
1304
+
1305
+ ---
1306
+
1307
+ ## CONTEXT`,
1172
1308
  user: `{{USER_PROMPT}}`
1173
1309
  }
1174
1310
  };
@@ -1904,6 +2040,7 @@ var AuthVerifyRequestMessageSchema = import_zod3.z.object({
1904
2040
  });
1905
2041
  var UserPromptRequestPayloadSchema = import_zod3.z.object({
1906
2042
  prompt: import_zod3.z.string(),
2043
+ userId: import_zod3.z.string().optional(),
1907
2044
  SA_RUNTIME: import_zod3.z.object({
1908
2045
  threadId: import_zod3.z.string(),
1909
2046
  uiBlockId: import_zod3.z.string()
@@ -1918,6 +2055,7 @@ var UserPromptRequestMessageSchema = import_zod3.z.object({
1918
2055
  });
1919
2056
  var UserPromptSuggestionsPayloadSchema = import_zod3.z.object({
1920
2057
  prompt: import_zod3.z.string(),
2058
+ userId: import_zod3.z.string().optional(),
1921
2059
  limit: import_zod3.z.number().int().positive().default(5),
1922
2060
  similarityThreshold: import_zod3.z.number().min(0).max(1).default(0.4)
1923
2061
  });
@@ -2007,6 +2145,7 @@ var UILogsMessageSchema = import_zod3.z.object({
2007
2145
  payload: UILogsPayloadSchema
2008
2146
  });
2009
2147
  var ActionsRequestPayloadSchema = import_zod3.z.object({
2148
+ userId: import_zod3.z.string().optional(),
2010
2149
  SA_RUNTIME: import_zod3.z.object({
2011
2150
  threadId: import_zod3.z.string(),
2012
2151
  uiBlockId: import_zod3.z.string()
@@ -2207,10 +2346,15 @@ var KbNodesRequestMessageSchema = import_zod3.z.object({
2207
2346
  });
2208
2347
  var DashCompRequestPayloadSchema = import_zod3.z.object({
2209
2348
  prompt: import_zod3.z.string(),
2349
+ userId: import_zod3.z.string().optional(),
2210
2350
  SA_RUNTIME: import_zod3.z.object({
2211
2351
  threadId: import_zod3.z.string().optional(),
2212
2352
  uiBlockId: import_zod3.z.string().optional()
2213
- }).optional()
2353
+ }).optional(),
2354
+ /** Existing components in the dashboard (for update/filter operations) */
2355
+ existingComponents: import_zod3.z.array(ComponentSchema).optional(),
2356
+ /** Request type: create (new component), update (modify existing), filter (create filter + update components) */
2357
+ req_type: import_zod3.z.enum(["create", "update", "filter"]).optional()
2214
2358
  });
2215
2359
  var DashCompRequestMessageSchema = import_zod3.z.object({
2216
2360
  id: import_zod3.z.string(),
@@ -7353,7 +7497,7 @@ var CONTEXT_CONFIG = {
7353
7497
  };
7354
7498
 
7355
7499
  // src/handlers/user-prompt-request.ts
7356
- var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, userId) => {
7500
+ var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools) => {
7357
7501
  const errors = [];
7358
7502
  logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
7359
7503
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
@@ -7367,6 +7511,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7367
7511
  const userPromptRequest = parseResult.data;
7368
7512
  const { id, payload } = userPromptRequest;
7369
7513
  const prompt = payload.prompt;
7514
+ const userId = payload.userId;
7370
7515
  const SA_RUNTIME = payload.SA_RUNTIME;
7371
7516
  const wsId = userPromptRequest.from.id || "unknown";
7372
7517
  const promptContext = `User Prompt: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
@@ -7539,8 +7684,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7539
7684
  wsId
7540
7685
  };
7541
7686
  };
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);
7687
+ async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools) {
7688
+ const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools);
7544
7689
  sendDataResponse4(
7545
7690
  response.id || data.id,
7546
7691
  {
@@ -7572,11 +7717,11 @@ function sendDataResponse4(id, res, sendMessage, clientId) {
7572
7717
 
7573
7718
  // src/handlers/user-prompt-suggestions.ts
7574
7719
  init_logger();
7575
- async function handleUserPromptSuggestions(data, components, sendMessage, collections, userId) {
7720
+ async function handleUserPromptSuggestions(data, components, sendMessage, collections) {
7576
7721
  try {
7577
7722
  const request = UserPromptSuggestionsMessageSchema.parse(data);
7578
7723
  const { id, payload, from } = request;
7579
- const { prompt, limit = 10 } = payload;
7724
+ const { prompt, userId, limit = 10 } = payload;
7580
7725
  const wsId = from.id;
7581
7726
  logger.info(`[USER_PROMPT_SUGGESTIONS_REQ ${id}] Processing user prompt suggestions: ${prompt}`);
7582
7727
  if (!prompt || prompt.trim().length === 0) {
@@ -10216,40 +10361,108 @@ function sendResponse8(id, res, sendMessage, clientId) {
10216
10361
  sendMessage(response);
10217
10362
  }
10218
10363
 
10219
- // src/handlers/dash-comp-request.ts
10364
+ // src/dashComp/index.ts
10220
10365
  init_logger();
10221
- init_prompt_loader();
10366
+
10367
+ // src/dashComp/types.ts
10222
10368
  var DEFAULT_DASH_COMP_MODELS = {
10223
10369
  anthropic: "anthropic/claude-haiku-4-5-20251001",
10224
10370
  gemini: "gemini/gemini-3-flash-preview",
10225
10371
  openai: "openai/gpt-4o-mini",
10226
10372
  groq: "groq/llama-3.3-70b-versatile"
10227
10373
  };
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}
10374
+
10375
+ // src/dashComp/utils.ts
10376
+ function getApiKeyAndModel(anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, dashCompModels) {
10377
+ const providers = llmProviders || ["anthropic", "gemini", "openai", "groq"];
10378
+ let apiKey;
10379
+ let model;
10380
+ if (dashCompModels?.model) {
10381
+ model = dashCompModels.model;
10382
+ const modelProvider = model.split("/")[0];
10383
+ if (modelProvider === "anthropic") apiKey = anthropicApiKey;
10384
+ else if (modelProvider === "gemini") apiKey = geminiApiKey;
10385
+ else if (modelProvider === "openai") apiKey = openaiApiKey;
10386
+ else if (modelProvider === "groq") apiKey = groqApiKey;
10387
+ } else {
10388
+ for (const provider of providers) {
10389
+ if (provider === "anthropic" && anthropicApiKey) {
10390
+ apiKey = anthropicApiKey;
10391
+ model = DEFAULT_DASH_COMP_MODELS.anthropic;
10392
+ break;
10393
+ } else if (provider === "gemini" && geminiApiKey) {
10394
+ apiKey = geminiApiKey;
10395
+ model = DEFAULT_DASH_COMP_MODELS.gemini;
10396
+ break;
10397
+ } else if (provider === "openai" && openaiApiKey) {
10398
+ apiKey = openaiApiKey;
10399
+ model = DEFAULT_DASH_COMP_MODELS.openai;
10400
+ break;
10401
+ } else if (provider === "groq" && groqApiKey) {
10402
+ apiKey = groqApiKey;
10403
+ model = DEFAULT_DASH_COMP_MODELS.groq;
10404
+ break;
10405
+ }
10406
+ }
10407
+ }
10408
+ return { apiKey, model };
10409
+ }
10410
+ function formatComponentsForPrompt(components) {
10411
+ if (!components || components.length === 0) {
10412
+ return "No components available";
10413
+ }
10414
+ return components.map((comp, idx) => {
10415
+ const keywords = comp.keywords ? comp.keywords.join(", ") : "";
10416
+ const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
10417
+ return `${idx + 1}. ID: ${comp.id}
10236
10418
  Name: ${comp.name}
10237
10419
  Type: ${comp.type}
10238
10420
  Description: ${comp.description || "No description"}
10239
10421
  Keywords: ${keywords}
10240
10422
  Props Structure: ${propsPreview}`;
10241
- }).join("\n\n");
10423
+ }).join("\n\n");
10424
+ }
10425
+ function formatToolsForPrompt(tools) {
10426
+ if (!tools || tools.length === 0) {
10427
+ return "No external tools available.";
10242
10428
  }
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}
10429
+ return tools.map((tool, idx) => {
10430
+ const paramsStr = Object.entries(tool.params || {}).map(([key, type]) => `${key}: ${type}`).join(", ");
10431
+ return `${idx + 1}. ID: ${tool.id}
10248
10432
  Name: ${tool.name}
10249
10433
  Description: ${tool.description}
10250
10434
  Parameters: { ${paramsStr} }`;
10251
- }).join("\n\n");
10435
+ }).join("\n\n");
10436
+ }
10437
+ function formatExistingComponentsForPrompt(existingComponents) {
10438
+ if (!existingComponents || existingComponents.length === 0) {
10439
+ return "No existing components in dashboard";
10252
10440
  }
10441
+ return JSON.stringify(existingComponents, null, 2);
10442
+ }
10443
+ function sendDashCompResponse(id, res, sendMessage, clientId) {
10444
+ const response = {
10445
+ id,
10446
+ type: "DASH_COMP_RES",
10447
+ from: { type: "data-agent" },
10448
+ to: {
10449
+ type: "runtime",
10450
+ id: clientId
10451
+ },
10452
+ payload: {
10453
+ ...res
10454
+ }
10455
+ };
10456
+ sendMessage(response);
10457
+ }
10458
+
10459
+ // src/dashComp/pick-component.ts
10460
+ init_logger();
10461
+ init_prompt_loader();
10462
+ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, _collections, tools, dashCompModels) {
10463
+ const errors = [];
10464
+ const availableComponentsText = formatComponentsForPrompt(components);
10465
+ const availableToolsText = formatToolsForPrompt(tools);
10253
10466
  try {
10254
10467
  const schemaDoc = schema.generateSchemaDocumentation();
10255
10468
  const databaseRules = await promptLoader.loadDatabaseRules();
@@ -10261,38 +10474,14 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10261
10474
  AVAILABLE_TOOLS: availableToolsText
10262
10475
  });
10263
10476
  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
- }
10477
+ const { apiKey, model } = getApiKeyAndModel(
10478
+ anthropicApiKey,
10479
+ groqApiKey,
10480
+ geminiApiKey,
10481
+ openaiApiKey,
10482
+ llmProviders,
10483
+ dashCompModels
10484
+ );
10296
10485
  if (!apiKey || !model) {
10297
10486
  errors.push("No API key available for any LLM provider");
10298
10487
  return { success: false, errors };
@@ -10323,13 +10512,13 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10323
10512
  });
10324
10513
  return { success: false, errors };
10325
10514
  }
10326
- const originalComponent = components.find((c) => c.id === result.componentId);
10515
+ const originalComponent = components.find((c) => c.name === result.componentName);
10327
10516
  if (!originalComponent) {
10328
- errors.push(`Component ${result.componentId} not found in available components`);
10517
+ errors.push(`Component ${result.componentName} not found in available components`);
10329
10518
  userPromptErrorLogger.logError("DASH_COMP_REQ", "Component not found", {
10330
10519
  prompt,
10331
- componentId: result.componentId,
10332
- availableComponentIds: components.map((c) => c.id)
10520
+ componentName: result.componentName,
10521
+ availableComponentNames: components.map((c) => c.name)
10333
10522
  });
10334
10523
  return { success: false, errors };
10335
10524
  }
@@ -10352,7 +10541,8 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10352
10541
  data: {
10353
10542
  component: finalComponent,
10354
10543
  reasoning: result.reasoning || "Component selected based on user prompt",
10355
- dataSource: result.props.query ? "database" : result.props.externalTool ? "external_tool" : "none"
10544
+ dataSource: result.props.query ? "database" : result.props.externalTool ? "external_tool" : "none",
10545
+ isUpdate: result.isUpdate || false
10356
10546
  },
10357
10547
  errors: []
10358
10548
  };
@@ -10368,6 +10558,84 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10368
10558
  return { success: false, errors };
10369
10559
  }
10370
10560
  }
10561
+
10562
+ // src/dashComp/create-filter.ts
10563
+ init_logger();
10564
+ init_prompt_loader();
10565
+ async function createFilterWithLLM(prompt, components, existingComponents, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, tools, dashCompModels) {
10566
+ const errors = [];
10567
+ try {
10568
+ const filterComponents = components.filter((c) => c.type.startsWith("Filter"));
10569
+ if (filterComponents.length === 0) {
10570
+ errors.push("No filter components available");
10571
+ return { success: false, errors };
10572
+ }
10573
+ logger.debug(`[DASH_COMP_REQ:FILTER] Found ${filterComponents.length} filter components`);
10574
+ const schemaDoc = schema.generateSchemaDocumentation();
10575
+ const databaseRules = await promptLoader.loadDatabaseRules();
10576
+ const prompts = await promptLoader.loadPrompts("dash-filter-picker", {
10577
+ USER_PROMPT: prompt,
10578
+ AVAILABLE_COMPONENTS: formatComponentsForPrompt(filterComponents),
10579
+ EXISTING_COMPONENTS: formatExistingComponentsForPrompt(existingComponents),
10580
+ SCHEMA_DOC: schemaDoc || "No database schema available",
10581
+ DATABASE_RULES: databaseRules,
10582
+ AVAILABLE_TOOLS: formatToolsForPrompt(tools)
10583
+ });
10584
+ logger.debug("[DASH_COMP_REQ:FILTER] Loaded dash-filter-picker prompts");
10585
+ const { apiKey, model } = getApiKeyAndModel(
10586
+ anthropicApiKey,
10587
+ groqApiKey,
10588
+ geminiApiKey,
10589
+ openaiApiKey,
10590
+ llmProviders,
10591
+ dashCompModels
10592
+ );
10593
+ if (!apiKey || !model) {
10594
+ errors.push("No API key available for any LLM provider");
10595
+ return { success: false, errors };
10596
+ }
10597
+ logger.info(`[DASH_COMP_REQ:FILTER] Using model: ${model}`);
10598
+ const result = await LLM.stream(
10599
+ { sys: prompts.system, user: prompts.user },
10600
+ { model, maxTokens: 16384, temperature: 0.2, apiKey },
10601
+ true
10602
+ );
10603
+ logger.debug("[DASH_COMP_REQ:FILTER] LLM response received");
10604
+ logger.file("[DASH_COMP_REQ:FILTER] LLM response:", JSON.stringify(result, null, 2));
10605
+ if (!result.filterComponent) {
10606
+ errors.push("Invalid LLM response: missing filterComponent");
10607
+ userPromptErrorLogger.logError("DASH_COMP_REQ:FILTER", "Invalid LLM response structure", {
10608
+ prompt,
10609
+ result,
10610
+ missingFields: { filterComponent: !result.filterComponent }
10611
+ });
10612
+ return { success: false, errors };
10613
+ }
10614
+ logger.info(`[DASH_COMP_REQ:FILTER] Successfully created filter: ${result.filterComponent.componentType}`);
10615
+ logger.info(`[DASH_COMP_REQ:FILTER] Updated ${result.updatedComponents?.length || 0} components`);
10616
+ return {
10617
+ success: true,
10618
+ data: {
10619
+ filterComponent: result.filterComponent,
10620
+ updatedComponents: result.updatedComponents || [],
10621
+ filterBindings: result.filterBindings || {},
10622
+ reasoning: result.reasoning || "Filter created based on user prompt"
10623
+ },
10624
+ errors: []
10625
+ };
10626
+ } catch (error) {
10627
+ const errorMsg = error instanceof Error ? error.message : String(error);
10628
+ logger.error(`[DASH_COMP_REQ:FILTER] Error creating filter: ${errorMsg}`);
10629
+ userPromptErrorLogger.logError("DASH_COMP_REQ:FILTER", error instanceof Error ? error : new Error(errorMsg), {
10630
+ prompt,
10631
+ existingComponentsCount: existingComponents.length
10632
+ });
10633
+ errors.push(errorMsg);
10634
+ return { success: false, errors };
10635
+ }
10636
+ }
10637
+
10638
+ // src/dashComp/index.ts
10371
10639
  var processDashCompRequest = async (data, components, _sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools, dashCompModels) => {
10372
10640
  const errors = [];
10373
10641
  logger.debug("[DASH_COMP_REQ] Parsing incoming message data");
@@ -10382,17 +10650,25 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10382
10650
  const dashCompRequest = parseResult.data;
10383
10651
  const { id, payload } = dashCompRequest;
10384
10652
  const prompt = payload.prompt;
10653
+ const reqType = payload.req_type || "create";
10654
+ const existingComponents = payload.existingComponents || [];
10385
10655
  const wsId = dashCompRequest.from.id || "unknown";
10386
- const promptContext = `DASH_COMP: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
10656
+ const promptContext = `DASH_COMP[${reqType}]: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
10387
10657
  llmUsageLogger.resetLogFile(promptContext);
10388
10658
  if (!prompt) {
10389
10659
  errors.push("Prompt is required");
10390
10660
  }
10661
+ if (reqType === "filter" && existingComponents.length === 0) {
10662
+ errors.push("Filter request requires existingComponents");
10663
+ }
10391
10664
  if (errors.length > 0) {
10392
10665
  return { success: false, errors, id, wsId };
10393
10666
  }
10394
- logger.info(`[DASH_COMP_REQ] Processing request for prompt: "${prompt.substring(0, 50)}..."`);
10667
+ logger.info(`[DASH_COMP_REQ] Processing ${reqType} request for prompt: "${prompt.substring(0, 50)}..."`);
10395
10668
  logger.info(`[DASH_COMP_REQ] Available: ${components?.length || 0} components, ${tools?.length || 0} tools`);
10669
+ if (existingComponents.length > 0) {
10670
+ logger.info(`[DASH_COMP_REQ] Existing components in dashboard: ${existingComponents.length}`);
10671
+ }
10396
10672
  if (!components || components.length === 0) {
10397
10673
  logger.warn("[DASH_COMP_REQ] No components available");
10398
10674
  return {
@@ -10402,19 +10678,35 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10402
10678
  wsId
10403
10679
  };
10404
10680
  }
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)}`);
10681
+ let llmResponse;
10682
+ if (reqType === "filter") {
10683
+ llmResponse = await createFilterWithLLM(
10684
+ prompt,
10685
+ components,
10686
+ existingComponents,
10687
+ anthropicApiKey,
10688
+ groqApiKey,
10689
+ geminiApiKey,
10690
+ openaiApiKey,
10691
+ llmProviders,
10692
+ tools,
10693
+ dashCompModels
10694
+ );
10695
+ } else {
10696
+ llmResponse = await pickComponentWithLLM(
10697
+ prompt,
10698
+ components,
10699
+ anthropicApiKey,
10700
+ groqApiKey,
10701
+ geminiApiKey,
10702
+ openaiApiKey,
10703
+ llmProviders,
10704
+ collections,
10705
+ tools,
10706
+ dashCompModels
10707
+ );
10708
+ }
10709
+ llmUsageLogger.logSessionSummary(`DASH_COMP[${reqType}]: ${prompt?.substring(0, 30)}`);
10418
10710
  return {
10419
10711
  success: llmResponse.success,
10420
10712
  data: llmResponse.data,
@@ -10447,22 +10739,7 @@ async function handleDashCompRequest(data, components, sendMessage, anthropicApi
10447
10739
  sendMessage,
10448
10740
  response.wsId || data.from?.id
10449
10741
  );
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}`);
10742
+ logger.info(`[DASH_COMP_REQ] Response sent to client ${response.wsId || data.from?.id}`);
10466
10743
  }
10467
10744
 
10468
10745
  // src/auth/user-manager.ts
@@ -11310,7 +11587,6 @@ var SuperatomSDK = class {
11310
11587
  }
11311
11588
  this.apiKey = config.apiKey;
11312
11589
  this.projectId = config.projectId;
11313
- this.userId = config.userId || "anonymous";
11314
11590
  this.type = config.type || "data-agent";
11315
11591
  this.bundleDir = config.bundleDir;
11316
11592
  this.url = config.url || process.env.SA_WEBSOCKET_URL || DEFAULT_WS_URL;
@@ -11412,7 +11688,6 @@ var SuperatomSDK = class {
11412
11688
  url.searchParams.set("apiKey", this.apiKey);
11413
11689
  }
11414
11690
  url.searchParams.set("projectId", this.projectId);
11415
- url.searchParams.set("userId", this.userId);
11416
11691
  url.searchParams.set("type", this.type);
11417
11692
  logger.info(`Connecting to WebSocket: ${url.toString()}`);
11418
11693
  this.ws = createWebSocket(url.toString());
@@ -11473,7 +11748,7 @@ var SuperatomSDK = class {
11473
11748
  });
11474
11749
  break;
11475
11750
  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) => {
11751
+ 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
11752
  logger.error("Failed to handle user prompt request:", error);
11478
11753
  });
11479
11754
  break;
@@ -11483,7 +11758,7 @@ var SuperatomSDK = class {
11483
11758
  });
11484
11759
  break;
11485
11760
  case "USER_PROMPT_SUGGESTIONS_REQ":
11486
- handleUserPromptSuggestions(parsed, this.components, (msg) => this.send(msg), this.collections, this.userId).catch((error) => {
11761
+ handleUserPromptSuggestions(parsed, this.components, (msg) => this.send(msg), this.collections).catch((error) => {
11487
11762
  logger.error("Failed to handle user prompt suggestions request:", error);
11488
11763
  });
11489
11764
  break;