@superatomai/sdk-node 0.0.63 → 0.0.64

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
@@ -6372,11 +6372,11 @@ Fixed SQL query:`;
6372
6372
  logger.info(`[${this.getProviderName()}] Passing ${deferredTools.length} deferred tools to component matching`);
6373
6373
  deferredToolsText = "The following external tools need user input via a Form component.\n**IMPORTANT: Use these EXACT values when generating Form externalTool prop.**\n\n" + deferredTools.map((tool, idx) => {
6374
6374
  return `${idx + 1}. **${tool.name}**
6375
- toolId: "${tool.id}" (USE THIS EXACT VALUE - do not modify!)
6376
- toolName: "${tool.name}"
6377
- parameters: ${JSON.stringify(tool.params || {})}
6378
- requiredFields:
6379
- ${JSON.stringify(tool.requiredFields || [], null, 2)}`;
6375
+ toolId: "${tool.id}" (USE THIS EXACT VALUE - do not modify!)
6376
+ toolName: "${tool.name}"
6377
+ parameters: ${JSON.stringify(tool.params || {})}
6378
+ requiredFields:
6379
+ ${JSON.stringify(tool.requiredFields || [], null, 2)}`;
6380
6380
  }).join("\n\n");
6381
6381
  }
6382
6382
  let executedToolsText = "No external tools were executed for data fetching.";
@@ -6392,8 +6392,8 @@ ${JSON.stringify(tool.requiredFields || [], null, 2)}`;
6392
6392
  const numericFields = fields.filter((f) => f.type === "number").map((f) => f.name);
6393
6393
  const stringFields = fields.filter((f) => f.type === "string").map((f) => f.name);
6394
6394
  fieldNamesList = `
6395
- \u{1F4CA} NUMERIC FIELDS (use for yAxisKey, valueKey, aggregationField): ${numericFields.join(", ") || "none"}
6396
- \u{1F4DD} STRING FIELDS (use for xAxisKey, groupBy, nameKey): ${stringFields.join(", ") || "none"}`;
6395
+ \u{1F4CA} NUMERIC FIELDS (use for yAxisKey, valueKey, aggregationField): ${numericFields.join(", ") || "none"}
6396
+ \u{1F4DD} STRING FIELDS (use for xAxisKey, groupBy, nameKey): ${stringFields.join(", ") || "none"}`;
6397
6397
  const fieldsText = fields.map(
6398
6398
  (f) => ` "${f.name}" (${f.type}): ${f.description}`
6399
6399
  ).join("\n");
@@ -6402,11 +6402,11 @@ ${JSON.stringify(tool.requiredFields || [], null, 2)}`;
6402
6402
  ${fieldsText}`;
6403
6403
  }
6404
6404
  return `${idx + 1}. **${tool.name}**
6405
- toolId: "${tool.id}"
6406
- toolName: "${tool.name}"
6407
- parameters: ${JSON.stringify(tool.params || {})}
6408
- recordCount: ${recordCount} rows returned
6409
- outputSchema: ${outputSchemaText}${fieldNamesList}`;
6405
+ toolId: "${tool.id}"
6406
+ toolName: "${tool.name}"
6407
+ parameters: ${JSON.stringify(tool.params || {})}
6408
+ recordCount: ${recordCount} rows returned
6409
+ outputSchema: ${outputSchemaText}${fieldNamesList}`;
6410
6410
  }).join("\n\n");
6411
6411
  }
6412
6412
  const schemaDoc = schema.generateSchemaDocumentation();
@@ -6457,6 +6457,7 @@ ${executedToolsText}`);
6457
6457
  logCollector?.info("Matching components from text response...");
6458
6458
  let fullResponseText = "";
6459
6459
  let answerComponentExtracted = false;
6460
+ let validatedAnswerComponent = null;
6460
6461
  const answerCallback = componentStreamCallback;
6461
6462
  const partialCallback = answerCallback ? (chunk) => {
6462
6463
  fullResponseText += chunk;
@@ -6515,8 +6516,8 @@ ${executedToolsText}`);
6515
6516
  }
6516
6517
  };
6517
6518
  const streamTime = (/* @__PURE__ */ new Date()).toISOString();
6518
- logger.info(`[${this.getProviderName()}] \u2713 [${streamTime}] Answer component detected in stream: ${answerComponent.name} (${answerComponent.type}) - STREAMING TO FRONTEND NOW`);
6519
- logCollector?.info(`\u2713 Answer component: ${answerComponent.name} (${answerComponent.type}) - streaming to frontend at ${streamTime}`);
6519
+ logger.info(`[${this.getProviderName()}] \u2713 [${streamTime}] Answer component detected in stream: ${answerComponent.name} (${answerComponent.type})`);
6520
+ logCollector?.info(`\u2713 Answer component: ${answerComponent.name} (${answerComponent.type}) - detected at ${streamTime}`);
6520
6521
  if (answerComponentData.props?.query) {
6521
6522
  logCollector?.logQuery(
6522
6523
  "Answer component query",
@@ -6524,7 +6525,79 @@ ${executedToolsText}`);
6524
6525
  { componentName: answerComponent.name, componentType: answerComponent.type, reasoning: answerComponentData.reasoning }
6525
6526
  );
6526
6527
  }
6527
- answerCallback(answerComponent);
6528
+ const answerQuery = answerComponent.props?.query;
6529
+ logger.info(`[${this.getProviderName()}] Answer component detected: ${answerComponent.name} (${answerComponent.type}), hasQuery: ${!!answerQuery}, hasDbExecute: ${!!collections?.["database"]?.["execute"]}`);
6530
+ if (answerQuery && collections?.["database"]?.["execute"]) {
6531
+ (async () => {
6532
+ const MAX_RETRIES = 3;
6533
+ let attempts = 0;
6534
+ let validated = false;
6535
+ let currentQuery = answerQuery;
6536
+ let currentQueryStr = typeof answerQuery === "string" ? answerQuery : answerQuery?.sql || "";
6537
+ let lastError = "";
6538
+ logger.info(`[${this.getProviderName()}] Validating answer component query before streaming...`);
6539
+ while (attempts < MAX_RETRIES && !validated) {
6540
+ attempts++;
6541
+ try {
6542
+ const cacheKey = this.getQueryCacheKey(currentQuery);
6543
+ if (cacheKey) {
6544
+ logger.debug(`[${this.getProviderName()}] Answer component query validation attempt ${attempts}/${MAX_RETRIES}`);
6545
+ const result2 = await collections["database"]["execute"]({ sql: cacheKey });
6546
+ queryCache.set(cacheKey, result2);
6547
+ validated = true;
6548
+ if (currentQuery !== answerQuery) {
6549
+ answerComponent.props.query = currentQuery;
6550
+ }
6551
+ validatedAnswerComponent = {
6552
+ componentId: answerComponentData.componentId,
6553
+ validatedQuery: currentQuery
6554
+ };
6555
+ logger.info(`[${this.getProviderName()}] \u2713 Answer component query validated (attempt ${attempts}) - STREAMING TO FRONTEND NOW`);
6556
+ logCollector?.info(`\u2713 Answer component query validated - streaming to frontend`);
6557
+ logger.info(`[${this.getProviderName()}] Calling answerCallback for: ${answerComponent.name}`);
6558
+ answerCallback(answerComponent);
6559
+ logger.info(`[${this.getProviderName()}] answerCallback completed for: ${answerComponent.name}`);
6560
+ }
6561
+ } catch (validationError) {
6562
+ lastError = validationError instanceof Error ? validationError.message : String(validationError);
6563
+ logger.warn(`[${this.getProviderName()}] Answer component query validation failed (attempt ${attempts}/${MAX_RETRIES}): ${lastError}`);
6564
+ if (attempts < MAX_RETRIES) {
6565
+ try {
6566
+ logger.info(`[${this.getProviderName()}] Requesting LLM to fix answer component query...`);
6567
+ const fixedQueryStr = await this.requestQueryFix(
6568
+ currentQueryStr,
6569
+ lastError,
6570
+ {
6571
+ name: answerComponent.name,
6572
+ type: answerComponent.type,
6573
+ title: answerComponent.props?.title
6574
+ },
6575
+ apiKey
6576
+ );
6577
+ if (typeof currentQuery === "string") {
6578
+ currentQuery = fixedQueryStr;
6579
+ } else {
6580
+ currentQuery = { ...currentQuery, sql: fixedQueryStr };
6581
+ }
6582
+ currentQueryStr = fixedQueryStr;
6583
+ logger.info(`[${this.getProviderName()}] LLM provided fixed query for answer component, retrying...`);
6584
+ } catch (fixError) {
6585
+ const fixErrorMsg = fixError instanceof Error ? fixError.message : String(fixError);
6586
+ logger.error(`[${this.getProviderName()}] Failed to get LLM query fix for answer component: ${fixErrorMsg}`);
6587
+ break;
6588
+ }
6589
+ }
6590
+ }
6591
+ }
6592
+ if (!validated) {
6593
+ logger.warn(`[${this.getProviderName()}] Answer component query validation failed after ${attempts} attempts - skipping early stream`);
6594
+ logCollector?.warn(`Answer component query validation failed: ${lastError} - will be handled in batch validation`);
6595
+ }
6596
+ })();
6597
+ } else {
6598
+ logger.info(`[${this.getProviderName()}] Answer component has no query - STREAMING TO FRONTEND NOW`);
6599
+ answerCallback(answerComponent);
6600
+ }
6528
6601
  answerComponentExtracted = true;
6529
6602
  }
6530
6603
  }
@@ -6578,6 +6651,10 @@ ${executedToolsText}`);
6578
6651
  return null;
6579
6652
  }
6580
6653
  let cleanedProps = { ...mc.props };
6654
+ if (validatedAnswerComponent && mc.componentId === validatedAnswerComponent.componentId) {
6655
+ logger.info(`[${this.getProviderName()}] Using pre-validated query for answer component: ${mc.componentId}`);
6656
+ cleanedProps.query = validatedAnswerComponent.validatedQuery;
6657
+ }
6581
6658
  if (cleanedProps.externalTool) {
6582
6659
  const toolId = cleanedProps.externalTool.toolId;
6583
6660
  const validToolIds = (executedTools || []).map((t) => t.id);
@@ -7623,11 +7700,14 @@ ${errorMsg}
7623
7700
  logger.info(`[${this.getProviderName()}] Generated ${actions.length} follow-up actions for general question`);
7624
7701
  } else if (components && components.length > 0) {
7625
7702
  logger.info(`[${this.getProviderName()}] Matching components from text response...`);
7703
+ logger.info(`[${this.getProviderName()}] componentStreamCallback setup: wrappedStreamCallback=${!!wrappedStreamCallback}, category=${category}`);
7626
7704
  const componentStreamCallback = wrappedStreamCallback && category !== "data_modification" ? (component) => {
7705
+ logger.info(`[${this.getProviderName()}] componentStreamCallback INVOKED for: ${component.name} (${component.type})`);
7627
7706
  const answerMarker = `__ANSWER_COMPONENT_START__${JSON.stringify(component)}__ANSWER_COMPONENT_END__`;
7628
7707
  wrappedStreamCallback(answerMarker);
7629
7708
  logger.info(`[${this.getProviderName()}] Streamed answer component to frontend: ${component.name} (${component.type})`);
7630
7709
  } : void 0;
7710
+ logger.info(`[${this.getProviderName()}] componentStreamCallback created: ${!!componentStreamCallback}`);
7631
7711
  const deferredTools = externalTools?.filter((t) => {
7632
7712
  if (t.executionType === "deferred" && !t.userProvidedData) return true;
7633
7713
  if (category === "data_modification" && !t.userProvidedData) {