@superatomai/sdk-node 0.0.77 → 0.0.79

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
@@ -402,7 +402,8 @@ var UserQueryFiltersSchema = import_zod3.z.object({
402
402
  username: import_zod3.z.string().optional(),
403
403
  email: import_zod3.z.string().optional(),
404
404
  role: import_zod3.z.string().optional(),
405
- fullname: import_zod3.z.string().optional()
405
+ fullname: import_zod3.z.string().optional(),
406
+ id: import_zod3.z.number().optional()
406
407
  });
407
408
  var UsersRequestPayloadSchema = import_zod3.z.object({
408
409
  operation: import_zod3.z.enum(["create", "update", "delete", "getAll", "getOne", "query"]),
@@ -752,6 +753,67 @@ var DashCompRequestMessageSchema = import_zod3.z.object({
752
753
  type: import_zod3.z.literal("DASH_COMP_REQ"),
753
754
  payload: DashCompRequestPayloadSchema
754
755
  });
756
+ var SchemaColumnStatisticsSchema = import_zod3.z.object({
757
+ distinct: import_zod3.z.number().optional(),
758
+ min: import_zod3.z.number().optional(),
759
+ max: import_zod3.z.number().optional()
760
+ });
761
+ var SchemaColumnSchema = import_zod3.z.object({
762
+ name: import_zod3.z.string(),
763
+ type: import_zod3.z.string(),
764
+ nativeType: import_zod3.z.string(),
765
+ nullable: import_zod3.z.boolean(),
766
+ description: import_zod3.z.string(),
767
+ statistics: SchemaColumnStatisticsSchema.optional(),
768
+ cardinality: import_zod3.z.enum(["unique", "high", "medium", "low"]).optional(),
769
+ sampleValues: import_zod3.z.array(import_zod3.z.string()).optional()
770
+ });
771
+ var SchemaTableSchema = import_zod3.z.object({
772
+ name: import_zod3.z.string(),
773
+ fullName: import_zod3.z.string(),
774
+ rowCount: import_zod3.z.number(),
775
+ description: import_zod3.z.string(),
776
+ columns: import_zod3.z.array(SchemaColumnSchema)
777
+ });
778
+ var SchemaRelationshipSchema = import_zod3.z.object({
779
+ from: import_zod3.z.string(),
780
+ to: import_zod3.z.string(),
781
+ type: import_zod3.z.string(),
782
+ keys: import_zod3.z.array(import_zod3.z.string())
783
+ });
784
+ var DatabaseSchemaSchema = import_zod3.z.object({
785
+ database: import_zod3.z.string(),
786
+ databaseType: import_zod3.z.string().optional(),
787
+ schema: import_zod3.z.string(),
788
+ description: import_zod3.z.string(),
789
+ tables: import_zod3.z.array(SchemaTableSchema),
790
+ relationships: import_zod3.z.array(SchemaRelationshipSchema).optional()
791
+ });
792
+ var SchemaRequestPayloadSchema = import_zod3.z.object({
793
+ /** If true, returns the formatted documentation string in addition to raw JSON */
794
+ formatted: import_zod3.z.boolean().optional()
795
+ });
796
+ var SchemaRequestMessageSchema = import_zod3.z.object({
797
+ id: import_zod3.z.string(),
798
+ from: MessageParticipantSchema,
799
+ type: import_zod3.z.literal("SCHEMA_REQ"),
800
+ payload: SchemaRequestPayloadSchema
801
+ });
802
+ var SchemaResponsePayloadSchema = import_zod3.z.object({
803
+ success: import_zod3.z.boolean(),
804
+ error: import_zod3.z.string().optional(),
805
+ data: import_zod3.z.object({
806
+ schema: DatabaseSchemaSchema,
807
+ /** Formatted schema documentation (only if formatted: true was requested) */
808
+ formatted: import_zod3.z.string().optional()
809
+ }).optional()
810
+ });
811
+ var SchemaResponseMessageSchema = import_zod3.z.object({
812
+ id: import_zod3.z.string(),
813
+ from: MessageParticipantSchema,
814
+ type: import_zod3.z.literal("SCHEMA_RES"),
815
+ payload: SchemaResponsePayloadSchema
816
+ });
755
817
 
756
818
  // src/utils/logger.ts
757
819
  var import_fs = __toESM(require("fs"));
@@ -3536,6 +3598,7 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
3536
3598
 
3537
3599
  **CRITICAL:**
3538
3600
  - Return ONLY valid JSON (no markdown code blocks, no text before/after)
3601
+ -\`componentName\`: MUST be the EXACT \`name\` field from the Available Components list. Never use a title or description as componentName.
3539
3602
  - \`componentId\`: For new components, MUST match an ID from the available components list. For updates, preserve the existing component's ID
3540
3603
  - \`isUpdate\`: Set to \`true\` if updating an existing component, \`false\` if creating new
3541
3604
  - \`dataSourceType\` indicates whether data comes from database or external tool
@@ -6533,6 +6596,7 @@ var STREAM_PREVIEW_MAX_CHARS = 200;
6533
6596
  var TOOL_TRACKING_MAX_ROWS = 5;
6534
6597
  var TOOL_TRACKING_MAX_CHARS = 200;
6535
6598
  var TOOL_TRACKING_SAMPLE_ROWS = 3;
6599
+ var DEFAULT_QUERY_LIMIT = 10;
6536
6600
  var MAX_COMPONENT_QUERY_LIMIT = 10;
6537
6601
  var EXACT_MATCH_SIMILARITY_THRESHOLD = 0.99;
6538
6602
  var DEFAULT_CONVERSATION_SIMILARITY_THRESHOLD = 0.8;
@@ -12223,6 +12287,7 @@ function formatComponentsForPrompt(components) {
12223
12287
  if (!components || components.length === 0) {
12224
12288
  return "No components available";
12225
12289
  }
12290
+ components = components.filter((c) => c.name !== "MultiComponentContainer");
12226
12291
  return components.map((comp, idx) => {
12227
12292
  const keywords = comp.keywords ? comp.keywords.join(", ") : "";
12228
12293
  const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
@@ -12269,7 +12334,7 @@ function sendDashCompResponse(id, res, sendMessage, clientId) {
12269
12334
  }
12270
12335
 
12271
12336
  // src/dashComp/pick-component.ts
12272
- async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, _collections, tools, dashCompModels) {
12337
+ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools, dashCompModels) {
12273
12338
  const errors = [];
12274
12339
  const availableComponentsText = formatComponentsForPrompt(components);
12275
12340
  const availableToolsText = formatToolsForPrompt(tools);
@@ -12325,7 +12390,8 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
12325
12390
  outputSchema: tool.outputSchema
12326
12391
  });
12327
12392
  logger.info(`[DASH_COMP_REQ] Tool ${tool.name} executed successfully`);
12328
- return JSON.stringify(result2, null, 2);
12393
+ const resultJson = JSON.stringify(result2, null, 2);
12394
+ return resultJson + "\n\n[REMINDER: The above is tool output for verification. You MUST still respond with ONLY the JSON component selection object. Do NOT summarize or describe these results.]";
12329
12395
  };
12330
12396
  const result = await LLM.streamWithTools(
12331
12397
  {
@@ -12343,16 +12409,59 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
12343
12409
  5
12344
12410
  // max iterations
12345
12411
  );
12346
- const jsonMatch = result.match(/\{[\s\S]*\}/);
12347
- const parsedResult = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
12412
+ let jsonMatch = result.match(/\{[\s\S]*\}/);
12413
+ let parsedResult = jsonMatch ? (() => {
12414
+ try {
12415
+ return JSON.parse(jsonMatch[0]);
12416
+ } catch {
12417
+ return null;
12418
+ }
12419
+ })() : null;
12420
+ const isValidComponent = parsedResult && parsedResult.componentId && parsedResult.props;
12421
+ if (!isValidComponent && executedTools.length > 0) {
12422
+ const toolDataSummary = executedTools.map(
12423
+ (t) => `Tool "${t.name}" was called with params ${JSON.stringify(t.params)} and returned:
12424
+ ${JSON.stringify(t.result, null, 2).substring(0, 5e3)}`
12425
+ ).join("\n\n");
12426
+ const retryUserPrompt = `Original user request: ${prompt}
12427
+
12428
+ The following tool was already called and returned data:
12429
+ ${toolDataSummary}
12430
+
12431
+ Using this data, select the appropriate component and respond with ONLY the JSON component selection object. No explanation, no markdown, just JSON.`;
12432
+ const retryResult = await LLM.text(
12433
+ {
12434
+ sys: prompts.system,
12435
+ user: retryUserPrompt
12436
+ },
12437
+ {
12438
+ model,
12439
+ maxTokens: 4096,
12440
+ temperature: 0.1,
12441
+ apiKey
12442
+ }
12443
+ );
12444
+ jsonMatch = retryResult.match(/\{[\s\S]*\}/);
12445
+ parsedResult = jsonMatch ? (() => {
12446
+ try {
12447
+ return JSON.parse(jsonMatch[0]);
12448
+ } catch {
12449
+ return null;
12450
+ }
12451
+ })() : null;
12452
+ }
12348
12453
  if (!parsedResult) {
12349
12454
  errors.push("Failed to parse LLM response as JSON");
12455
+ errors.push(`LLM Response: ${result}`);
12456
+ logger.error(`[DASH_COMP_REQ] Failed to parse JSON from LLM response`);
12350
12457
  return { success: false, errors };
12351
12458
  }
12352
- logger.debug("[DASH_COMP_REQ] LLM response received");
12459
+ logger.info(`[DASH_COMP_REQ] Parsed component: ${parsedResult.componentName} (${parsedResult.componentId})`);
12353
12460
  logger.file("[DASH_COMP_REQ] LLM response:", JSON.stringify(parsedResult, null, 2));
12354
12461
  if (!parsedResult.componentId || !parsedResult.props) {
12355
12462
  errors.push("Invalid LLM response: missing componentId or props");
12463
+ errors.push(`LLM Response: ${result}`);
12464
+ logger.error(`[DASH_COMP_REQ] Invalid structure - missing componentId: ${!parsedResult.componentId}, missing props: ${!parsedResult.props}`);
12356
12465
  userPromptErrorLogger.logError("DASH_COMP_REQ", "Invalid LLM response structure", {
12357
12466
  prompt,
12358
12467
  result: parsedResult,
@@ -12363,6 +12472,7 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
12363
12472
  const originalComponent = components.find((c) => c.name === parsedResult.componentName);
12364
12473
  if (!originalComponent) {
12365
12474
  errors.push(`Component ${parsedResult.componentName} not found in available components`);
12475
+ errors.push(`LLM Response: ${result}`);
12366
12476
  userPromptErrorLogger.logError("DASH_COMP_REQ", "Component not found", {
12367
12477
  prompt,
12368
12478
  componentName: parsedResult.componentName,
@@ -12370,14 +12480,72 @@ async function pickComponentWithLLM(prompt, components, anthropicApiKey, groqApi
12370
12480
  });
12371
12481
  return { success: false, errors };
12372
12482
  }
12373
- const finalComponent = {
12483
+ let finalComponent = {
12374
12484
  ...originalComponent,
12375
12485
  props: {
12376
12486
  ...originalComponent.props,
12377
12487
  ...parsedResult.props
12378
12488
  }
12379
12489
  };
12490
+ if (finalComponent.props?.query) {
12491
+ const query = finalComponent.props.query;
12492
+ if (typeof query === "string") {
12493
+ finalComponent.props.query = ensureQueryLimit(query, DEFAULT_QUERY_LIMIT, MAX_COMPONENT_QUERY_LIMIT);
12494
+ } else if (query?.sql) {
12495
+ finalComponent.props.query = {
12496
+ ...query,
12497
+ sql: ensureQueryLimit(query.sql, DEFAULT_QUERY_LIMIT, MAX_COMPONENT_QUERY_LIMIT)
12498
+ };
12499
+ }
12500
+ }
12380
12501
  logger.info(`[DASH_COMP_REQ] Successfully picked component: ${finalComponent.name} (${finalComponent.type})`);
12502
+ if (finalComponent.props?.query && collections?.["database"]?.["execute"]) {
12503
+ logger.info(`[DASH_COMP_REQ] Validating query for component: ${finalComponent.name}`);
12504
+ const queryService = new QueryExecutionService({
12505
+ defaultLimit: DEFAULT_QUERY_LIMIT,
12506
+ getModelForTask: () => model,
12507
+ // Use the same model for query fixes
12508
+ getApiKey: () => apiKey,
12509
+ providerName: "DASH_COMP_REQ"
12510
+ });
12511
+ try {
12512
+ const validationResult = await queryService.validateSingleQuery(
12513
+ finalComponent,
12514
+ collections,
12515
+ apiKey
12516
+ );
12517
+ if (!validationResult.validated) {
12518
+ logger.error(`[DASH_COMP_REQ] Query validation failed for component: ${finalComponent.name}`);
12519
+ errors.push(`Query validation failed for component ${finalComponent.name}. The generated SQL query could not be executed.`);
12520
+ return {
12521
+ success: false,
12522
+ errors,
12523
+ data: {
12524
+ reasoning: parsedResult.reasoning || "Component selected but query validation failed",
12525
+ rawResponse: parsedResult
12526
+ }
12527
+ };
12528
+ }
12529
+ if (validationResult.component) {
12530
+ finalComponent = validationResult.component;
12531
+ }
12532
+ logger.info(`[DASH_COMP_REQ] Query validated successfully for component: ${finalComponent.name}`);
12533
+ } catch (validationError) {
12534
+ const validationErrorMsg = validationError instanceof Error ? validationError.message : String(validationError);
12535
+ logger.error(`[DASH_COMP_REQ] Query validation error: ${validationErrorMsg}`);
12536
+ errors.push(`Query validation error: ${validationErrorMsg}`);
12537
+ return {
12538
+ success: false,
12539
+ errors,
12540
+ data: {
12541
+ reasoning: parsedResult.reasoning || "Component selected but query validation encountered an error",
12542
+ rawResponse: parsedResult
12543
+ }
12544
+ };
12545
+ }
12546
+ } else if (finalComponent.props?.query && !collections?.["database"]?.["execute"]) {
12547
+ logger.warn(`[DASH_COMP_REQ] Skipping query validation - database execute function not available`);
12548
+ }
12381
12549
  if (parsedResult.props.query) {
12382
12550
  logger.info(`[DASH_COMP_REQ] Data source: Database query`);
12383
12551
  }
@@ -12487,12 +12655,14 @@ async function createFilterWithLLM(prompt, components, existingComponents, anthr
12487
12655
  const result = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
12488
12656
  if (!result) {
12489
12657
  errors.push("Failed to parse LLM response as JSON");
12658
+ errors.push(`LLM Response: ${rawResult}`);
12490
12659
  return { success: false, errors };
12491
12660
  }
12492
12661
  logger.debug("[DASH_COMP_REQ:FILTER] LLM response received");
12493
12662
  logger.file("[DASH_COMP_REQ:FILTER] LLM response:", JSON.stringify(result, null, 2));
12494
12663
  if (!result.filterComponent) {
12495
12664
  errors.push("Invalid LLM response: missing filterComponent");
12665
+ errors.push(`LLM Response: ${rawResult}`);
12496
12666
  userPromptErrorLogger.logError("DASH_COMP_REQ:FILTER", "Invalid LLM response structure", {
12497
12667
  prompt,
12498
12668
  result,
@@ -12635,6 +12805,64 @@ async function handleDashCompRequest(data, components, sendMessage, anthropicApi
12635
12805
  logger.info(`[DASH_COMP_REQ] Response sent to client ${response.wsId || data.from?.id}`);
12636
12806
  }
12637
12807
 
12808
+ // src/handlers/schema-request.ts
12809
+ async function handleSchemaRequest(message, sendMessage) {
12810
+ const startTime = Date.now();
12811
+ try {
12812
+ const payload = message.payload;
12813
+ const formatted = payload?.formatted ?? false;
12814
+ logger.info(`[SchemaRequest] Processing schema request (formatted: ${formatted})`);
12815
+ const schemaData = schema.getSchema();
12816
+ if (!schemaData) {
12817
+ const response2 = {
12818
+ id: message.id,
12819
+ type: "SCHEMA_RES",
12820
+ from: { type: "data-agent" },
12821
+ to: message.from,
12822
+ payload: {
12823
+ success: false,
12824
+ error: "Schema not found or failed to load"
12825
+ }
12826
+ };
12827
+ sendMessage(response2);
12828
+ return;
12829
+ }
12830
+ const responseData = {
12831
+ schema: schemaData
12832
+ };
12833
+ if (formatted) {
12834
+ responseData.formatted = schema.generateSchemaDocumentation();
12835
+ }
12836
+ const executionMs = Date.now() - startTime;
12837
+ logger.info(`[SchemaRequest] Schema retrieved successfully in ${executionMs}ms`);
12838
+ const response = {
12839
+ id: message.id,
12840
+ type: "SCHEMA_RES",
12841
+ from: { type: "data-agent" },
12842
+ to: message.from,
12843
+ payload: {
12844
+ success: true,
12845
+ data: responseData
12846
+ }
12847
+ };
12848
+ sendMessage(response);
12849
+ } catch (error) {
12850
+ const errorMsg = error instanceof Error ? error.message : String(error);
12851
+ logger.error(`[SchemaRequest] Error: ${errorMsg}`);
12852
+ const response = {
12853
+ id: message.id,
12854
+ type: "SCHEMA_RES",
12855
+ from: { type: "data-agent" },
12856
+ to: message.from,
12857
+ payload: {
12858
+ success: false,
12859
+ error: errorMsg
12860
+ }
12861
+ };
12862
+ sendMessage(response);
12863
+ }
12864
+ }
12865
+
12638
12866
  // src/auth/user-manager.ts
12639
12867
  var import_fs6 = __toESM(require("fs"));
12640
12868
  var import_path5 = __toESM(require("path"));
@@ -13883,6 +14111,11 @@ var SuperatomSDK = class {
13883
14111
  logger.error("Failed to handle dash comp request:", error);
13884
14112
  });
13885
14113
  break;
14114
+ case "SCHEMA_REQ":
14115
+ handleSchemaRequest(parsed, (msg) => this.send(msg)).catch((error) => {
14116
+ logger.error("Failed to handle schema request:", error);
14117
+ });
14118
+ break;
13886
14119
  default:
13887
14120
  const handler = this.messageTypeHandlers.get(message.type);
13888
14121
  if (handler) {