@superatomai/sdk-node 0.0.41 → 0.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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
1163
1241
 
1164
- ### Database Schema
1242
+ Use this binding format to connect filter values to component params:
1243
+ \`\`\`json
1244
+ {
1245
+ "paramName": "$filter.filterId.value"
1246
+ }
1247
+ \`\`\`
1248
+
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
  });
@@ -1933,7 +2094,7 @@ var ComponentPropsSchema = import_zod3.z.object({
1933
2094
  description: import_zod3.z.string().optional(),
1934
2095
  config: import_zod3.z.record(import_zod3.z.unknown()).optional(),
1935
2096
  actions: import_zod3.z.array(import_zod3.z.any()).optional()
1936
- });
2097
+ }).passthrough();
1937
2098
  var ComponentSchema = import_zod3.z.object({
1938
2099
  id: import_zod3.z.string(),
1939
2100
  name: import_zod3.z.string(),
@@ -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(),
@@ -3458,9 +3625,9 @@ var PRICING = {
3458
3625
  "gpt-4": { input: 30, output: 60 },
3459
3626
  "gpt-3.5-turbo": { input: 0.5, output: 1.5 },
3460
3627
  // Google Gemini (December 2025)
3461
- "gemini-3-pro": { input: 2, output: 8 },
3628
+ "gemini-3-pro-preview": { input: 2, output: 12 },
3462
3629
  // New Gemini 3
3463
- "gemini-2.5-pro": { input: 1.25, output: 10 },
3630
+ "gemini-3-flash-preview": { input: 0.5, output: 3 },
3464
3631
  // For prompts ≤200K tokens, 2x for >200K
3465
3632
  "gemini-2.5-flash": { input: 0.15, output: 0.6 },
3466
3633
  // Standard mode (thinking disabled: $0.60, thinking enabled: $3.50)
@@ -4645,6 +4812,7 @@ var LLM = class {
4645
4812
  }
4646
4813
  }
4647
4814
  static async _geminiStreamWithTools(messages, tools, toolHandler, modelName, options, maxIterations) {
4815
+ const methodStartTime = Date.now();
4648
4816
  const apiKey = options.apiKey || process.env.GEMINI_API_KEY || "";
4649
4817
  const genAI = new import_generative_ai.GoogleGenerativeAI(apiKey);
4650
4818
  const systemPrompt = typeof messages.sys === "string" ? messages.sys : messages.sys.map((block) => block.text).join("\n");
@@ -4673,11 +4841,18 @@ var LLM = class {
4673
4841
  let iterations = 0;
4674
4842
  let finalText = "";
4675
4843
  let currentUserMessage = messages.user;
4844
+ let totalToolCalls = 0;
4845
+ let totalInputTokens = 0;
4846
+ let totalOutputTokens = 0;
4676
4847
  while (iterations < maxIterations) {
4677
4848
  iterations++;
4849
+ const iterationStartTime = Date.now();
4850
+ const requestId = llmUsageLogger.generateRequestId();
4678
4851
  const result = await chat.sendMessageStream(currentUserMessage);
4679
4852
  let responseText = "";
4680
4853
  const functionCalls = [];
4854
+ let inputTokens = 0;
4855
+ let outputTokens = 0;
4681
4856
  for await (const chunk of result.stream) {
4682
4857
  const candidate = chunk.candidates?.[0];
4683
4858
  if (!candidate) continue;
@@ -4694,7 +4869,37 @@ var LLM = class {
4694
4869
  });
4695
4870
  }
4696
4871
  }
4872
+ if (chunk.usageMetadata) {
4873
+ inputTokens = chunk.usageMetadata.promptTokenCount || 0;
4874
+ outputTokens = chunk.usageMetadata.candidatesTokenCount || 0;
4875
+ }
4876
+ }
4877
+ const iterationDuration = Date.now() - iterationStartTime;
4878
+ const toolCallsInIteration = functionCalls.length;
4879
+ totalToolCalls += toolCallsInIteration;
4880
+ if (inputTokens === 0) {
4881
+ const userMsg = typeof currentUserMessage === "string" ? currentUserMessage : JSON.stringify(currentUserMessage);
4882
+ inputTokens = Math.ceil((systemPrompt.length + userMsg.length) / 4);
4883
+ }
4884
+ if (outputTokens === 0) {
4885
+ outputTokens = Math.ceil(responseText.length / 4);
4697
4886
  }
4887
+ totalInputTokens += inputTokens;
4888
+ totalOutputTokens += outputTokens;
4889
+ llmUsageLogger.log({
4890
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4891
+ requestId,
4892
+ provider: "gemini",
4893
+ model: modelName,
4894
+ method: `streamWithTools[iter=${iterations}]`,
4895
+ inputTokens,
4896
+ outputTokens,
4897
+ totalTokens: inputTokens + outputTokens,
4898
+ costUSD: llmUsageLogger.calculateCost(modelName, inputTokens, outputTokens),
4899
+ durationMs: iterationDuration,
4900
+ toolCalls: toolCallsInIteration,
4901
+ success: true
4902
+ });
4698
4903
  if (functionCalls.length === 0) {
4699
4904
  finalText = responseText;
4700
4905
  break;
@@ -4727,6 +4932,23 @@ var LLM = class {
4727
4932
  }));
4728
4933
  currentUserMessage = functionResponseParts;
4729
4934
  }
4935
+ const totalDuration = Date.now() - methodStartTime;
4936
+ if (iterations > 1) {
4937
+ llmUsageLogger.log({
4938
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4939
+ requestId: llmUsageLogger.generateRequestId(),
4940
+ provider: "gemini",
4941
+ model: modelName,
4942
+ method: `streamWithTools[TOTAL:${iterations}iters]`,
4943
+ inputTokens: totalInputTokens,
4944
+ outputTokens: totalOutputTokens,
4945
+ totalTokens: totalInputTokens + totalOutputTokens,
4946
+ costUSD: llmUsageLogger.calculateCost(modelName, totalInputTokens, totalOutputTokens),
4947
+ durationMs: totalDuration,
4948
+ toolCalls: totalToolCalls,
4949
+ success: true
4950
+ });
4951
+ }
4730
4952
  if (iterations >= maxIterations) {
4731
4953
  throw new Error(`Max iterations (${maxIterations}) reached in tool calling loop`);
4732
4954
  }
@@ -6781,10 +7003,10 @@ var GeminiLLM = class extends BaseLLM {
6781
7003
  super(config);
6782
7004
  }
6783
7005
  getDefaultModel() {
6784
- return "gemini/gemini-2.5-flash";
7006
+ return "gemini/gemini-3-pro-preview";
6785
7007
  }
6786
7008
  getDefaultFastModel() {
6787
- return "gemini/gemini-2.0-flash-exp";
7009
+ return "gemini/gemini-3-flash-preview";
6788
7010
  }
6789
7011
  getDefaultApiKey() {
6790
7012
  return process.env.GEMINI_API_KEY;
@@ -7298,7 +7520,7 @@ var CONTEXT_CONFIG = {
7298
7520
  };
7299
7521
 
7300
7522
  // src/handlers/user-prompt-request.ts
7301
- 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) => {
7302
7524
  const errors = [];
7303
7525
  logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
7304
7526
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
@@ -7312,6 +7534,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7312
7534
  const userPromptRequest = parseResult.data;
7313
7535
  const { id, payload } = userPromptRequest;
7314
7536
  const prompt = payload.prompt;
7537
+ const userId = payload.userId;
7315
7538
  const SA_RUNTIME = payload.SA_RUNTIME;
7316
7539
  const wsId = userPromptRequest.from.id || "unknown";
7317
7540
  const promptContext = `User Prompt: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
@@ -7484,8 +7707,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
7484
7707
  wsId
7485
7708
  };
7486
7709
  };
7487
- async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, userId) {
7488
- 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);
7489
7712
  sendDataResponse4(
7490
7713
  response.id || data.id,
7491
7714
  {
@@ -7517,11 +7740,11 @@ function sendDataResponse4(id, res, sendMessage, clientId) {
7517
7740
 
7518
7741
  // src/handlers/user-prompt-suggestions.ts
7519
7742
  init_logger();
7520
- async function handleUserPromptSuggestions(data, components, sendMessage, collections, userId) {
7743
+ async function handleUserPromptSuggestions(data, components, sendMessage, collections) {
7521
7744
  try {
7522
7745
  const request = UserPromptSuggestionsMessageSchema.parse(data);
7523
7746
  const { id, payload, from } = request;
7524
- const { prompt, limit = 10 } = payload;
7747
+ const { prompt, userId, limit = 10 } = payload;
7525
7748
  const wsId = from.id;
7526
7749
  logger.info(`[USER_PROMPT_SUGGESTIONS_REQ ${id}] Processing user prompt suggestions: ${prompt}`);
7527
7750
  if (!prompt || prompt.trim().length === 0) {
@@ -10161,34 +10384,108 @@ function sendResponse8(id, res, sendMessage, clientId) {
10161
10384
  sendMessage(response);
10162
10385
  }
10163
10386
 
10164
- // src/handlers/dash-comp-request.ts
10387
+ // src/dashComp/index.ts
10165
10388
  init_logger();
10166
- init_prompt_loader();
10167
- async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, _collections, tools) {
10168
- const errors = [];
10169
- let availableComponentsText = "No components available";
10170
- if (components && components.length > 0) {
10171
- availableComponentsText = components.map((comp, idx) => {
10172
- const keywords = comp.keywords ? comp.keywords.join(", ") : "";
10173
- const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
10174
- return `${idx + 1}. ID: ${comp.id}
10389
+
10390
+ // src/dashComp/types.ts
10391
+ var DEFAULT_DASH_COMP_MODELS = {
10392
+ anthropic: "anthropic/claude-haiku-4-5-20251001",
10393
+ gemini: "gemini/gemini-3-flash-preview",
10394
+ openai: "openai/gpt-4o-mini",
10395
+ groq: "groq/llama-3.3-70b-versatile"
10396
+ };
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}
10175
10441
  Name: ${comp.name}
10176
10442
  Type: ${comp.type}
10177
10443
  Description: ${comp.description || "No description"}
10178
10444
  Keywords: ${keywords}
10179
10445
  Props Structure: ${propsPreview}`;
10180
- }).join("\n\n");
10446
+ }).join("\n\n");
10447
+ }
10448
+ function formatToolsForPrompt(tools) {
10449
+ if (!tools || tools.length === 0) {
10450
+ return "No external tools available.";
10181
10451
  }
10182
- let availableToolsText = "No external tools available.";
10183
- if (tools && tools.length > 0) {
10184
- availableToolsText = tools.map((tool, idx) => {
10185
- const paramsStr = Object.entries(tool.params || {}).map(([key, type]) => `${key}: ${type}`).join(", ");
10186
- 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}
10187
10455
  Name: ${tool.name}
10188
10456
  Description: ${tool.description}
10189
10457
  Parameters: { ${paramsStr} }`;
10190
- }).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";
10191
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);
10192
10489
  try {
10193
10490
  const schemaDoc = schema.generateSchemaDocumentation();
10194
10491
  const databaseRules = await promptLoader.loadDatabaseRules();
@@ -10200,29 +10497,15 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10200
10497
  AVAILABLE_TOOLS: availableToolsText
10201
10498
  });
10202
10499
  logger.debug("[DASH_COMP_REQ] Loaded dash-comp-picker prompts with schema and tools");
10203
- const providers = llmProviders || ["anthropic", "gemini", "openai", "groq"];
10204
- let apiKey;
10205
- let model = "anthropic/claude-sonnet-4-5-20250929";
10206
- for (const provider of providers) {
10207
- if (provider === "anthropic" && anthropicApiKey) {
10208
- apiKey = anthropicApiKey;
10209
- model = "anthropic/claude-sonnet-4-5-20250929";
10210
- break;
10211
- } else if (provider === "openai" && openaiApiKey) {
10212
- apiKey = openaiApiKey;
10213
- model = "openai/gpt-4o-mini";
10214
- break;
10215
- } else if (provider === "gemini" && geminiApiKey) {
10216
- apiKey = geminiApiKey;
10217
- model = "google/gemini-2.0-flash-001";
10218
- break;
10219
- } else if (provider === "groq" && groqApiKey) {
10220
- apiKey = groqApiKey;
10221
- model = "groq/llama-3.3-70b-versatile";
10222
- break;
10223
- }
10224
- }
10225
- if (!apiKey) {
10500
+ const { apiKey, model } = getApiKeyAndModel(
10501
+ anthropicApiKey,
10502
+ groqApiKey,
10503
+ geminiApiKey,
10504
+ openaiApiKey,
10505
+ llmProviders,
10506
+ dashCompModels
10507
+ );
10508
+ if (!apiKey || !model) {
10226
10509
  errors.push("No API key available for any LLM provider");
10227
10510
  return { success: false, errors };
10228
10511
  }
@@ -10245,11 +10528,21 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10245
10528
  logger.file("[DASH_COMP_REQ] LLM response:", JSON.stringify(result, null, 2));
10246
10529
  if (!result.componentId || !result.props) {
10247
10530
  errors.push("Invalid LLM response: missing componentId or props");
10531
+ userPromptErrorLogger.logError("DASH_COMP_REQ", "Invalid LLM response structure", {
10532
+ prompt,
10533
+ result,
10534
+ missingFields: { componentId: !result.componentId, props: !result.props }
10535
+ });
10248
10536
  return { success: false, errors };
10249
10537
  }
10250
10538
  const originalComponent = components.find((c) => c.id === result.componentId);
10251
10539
  if (!originalComponent) {
10252
10540
  errors.push(`Component ${result.componentId} not found in available components`);
10541
+ userPromptErrorLogger.logError("DASH_COMP_REQ", "Component not found", {
10542
+ prompt,
10543
+ componentId: result.componentId,
10544
+ availableComponentIds: components.map((c) => c.id)
10545
+ });
10253
10546
  return { success: false, errors };
10254
10547
  }
10255
10548
  const finalComponent = {
@@ -10271,18 +10564,102 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
10271
10564
  data: {
10272
10565
  component: finalComponent,
10273
10566
  reasoning: result.reasoning || "Component selected based on user prompt",
10274
- 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
10275
10569
  },
10276
10570
  errors: []
10277
10571
  };
10278
10572
  } catch (error) {
10279
10573
  const errorMsg = error instanceof Error ? error.message : String(error);
10280
10574
  logger.error(`[DASH_COMP_REQ] Error picking component: ${errorMsg}`);
10575
+ userPromptErrorLogger.logError("DASH_COMP_REQ", error instanceof Error ? error : new Error(errorMsg), {
10576
+ prompt,
10577
+ componentsCount: components.length,
10578
+ toolsCount: tools?.length || 0
10579
+ });
10580
+ errors.push(errorMsg);
10581
+ return { success: false, errors };
10582
+ }
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
+ });
10281
10656
  errors.push(errorMsg);
10282
10657
  return { success: false, errors };
10283
10658
  }
10284
10659
  }
10285
- var processDashCompRequest = async (data, components, _sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools) => {
10660
+
10661
+ // src/dashComp/index.ts
10662
+ var processDashCompRequest = async (data, components, _sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools, dashCompModels) => {
10286
10663
  const errors = [];
10287
10664
  logger.debug("[DASH_COMP_REQ] Parsing incoming message data");
10288
10665
  const parseResult = DashCompRequestMessageSchema.safeParse(data);
@@ -10296,15 +10673,25 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10296
10673
  const dashCompRequest = parseResult.data;
10297
10674
  const { id, payload } = dashCompRequest;
10298
10675
  const prompt = payload.prompt;
10676
+ const reqType = payload.req_type || "create";
10677
+ const existingComponents = payload.existingComponents || [];
10299
10678
  const wsId = dashCompRequest.from.id || "unknown";
10679
+ const promptContext = `DASH_COMP[${reqType}]: ${prompt?.substring(0, 50)}${(prompt?.length || 0) > 50 ? "..." : ""}`;
10680
+ llmUsageLogger.resetLogFile(promptContext);
10300
10681
  if (!prompt) {
10301
10682
  errors.push("Prompt is required");
10302
10683
  }
10684
+ if (reqType === "filter" && existingComponents.length === 0) {
10685
+ errors.push("Filter request requires existingComponents");
10686
+ }
10303
10687
  if (errors.length > 0) {
10304
10688
  return { success: false, errors, id, wsId };
10305
10689
  }
10306
- 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)}..."`);
10307
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
+ }
10308
10695
  if (!components || components.length === 0) {
10309
10696
  logger.warn("[DASH_COMP_REQ] No components available");
10310
10697
  return {
@@ -10314,17 +10701,35 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10314
10701
  wsId
10315
10702
  };
10316
10703
  }
10317
- const llmResponse = await pickComponentWithLLM(
10318
- prompt,
10319
- components,
10320
- anthropicApiKey,
10321
- groqApiKey,
10322
- geminiApiKey,
10323
- openaiApiKey,
10324
- llmProviders,
10325
- collections,
10326
- tools
10327
- );
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)}`);
10328
10733
  return {
10329
10734
  success: llmResponse.success,
10330
10735
  data: llmResponse.data,
@@ -10333,7 +10738,7 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
10333
10738
  wsId
10334
10739
  };
10335
10740
  };
10336
- async function handleDashCompRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools) {
10741
+ async function handleDashCompRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools, dashCompModels) {
10337
10742
  const response = await processDashCompRequest(
10338
10743
  data,
10339
10744
  components,
@@ -10344,7 +10749,8 @@ async function handleDashCompRequest(data, components, sendMessage, anthropicApi
10344
10749
  openaiApiKey,
10345
10750
  llmProviders,
10346
10751
  collections,
10347
- tools
10752
+ tools,
10753
+ dashCompModels
10348
10754
  );
10349
10755
  sendDashCompResponse(
10350
10756
  response.id || data.id,
@@ -10356,22 +10762,7 @@ async function handleDashCompRequest(data, components, sendMessage, anthropicApi
10356
10762
  sendMessage,
10357
10763
  response.wsId || data.from?.id
10358
10764
  );
10359
- }
10360
- function sendDashCompResponse(id, res, sendMessage, clientId) {
10361
- const response = {
10362
- id,
10363
- type: "DASH_COMP_RES",
10364
- from: { type: "data-agent" },
10365
- to: {
10366
- type: "runtime",
10367
- id: clientId
10368
- },
10369
- payload: {
10370
- ...res
10371
- }
10372
- };
10373
- sendMessage(response);
10374
- 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}`);
10375
10766
  }
10376
10767
 
10377
10768
  // src/auth/user-manager.ts
@@ -11219,7 +11610,6 @@ var SuperatomSDK = class {
11219
11610
  }
11220
11611
  this.apiKey = config.apiKey;
11221
11612
  this.projectId = config.projectId;
11222
- this.userId = config.userId || "anonymous";
11223
11613
  this.type = config.type || "data-agent";
11224
11614
  this.bundleDir = config.bundleDir;
11225
11615
  this.url = config.url || process.env.SA_WEBSOCKET_URL || DEFAULT_WS_URL;
@@ -11321,7 +11711,6 @@ var SuperatomSDK = class {
11321
11711
  url.searchParams.set("apiKey", this.apiKey);
11322
11712
  }
11323
11713
  url.searchParams.set("projectId", this.projectId);
11324
- url.searchParams.set("userId", this.userId);
11325
11714
  url.searchParams.set("type", this.type);
11326
11715
  logger.info(`Connecting to WebSocket: ${url.toString()}`);
11327
11716
  this.ws = createWebSocket(url.toString());
@@ -11382,7 +11771,7 @@ var SuperatomSDK = class {
11382
11771
  });
11383
11772
  break;
11384
11773
  case "USER_PROMPT_REQ":
11385
- 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) => {
11386
11775
  logger.error("Failed to handle user prompt request:", error);
11387
11776
  });
11388
11777
  break;
@@ -11392,7 +11781,7 @@ var SuperatomSDK = class {
11392
11781
  });
11393
11782
  break;
11394
11783
  case "USER_PROMPT_SUGGESTIONS_REQ":
11395
- 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) => {
11396
11785
  logger.error("Failed to handle user prompt suggestions request:", error);
11397
11786
  });
11398
11787
  break;