@superatomai/sdk-node 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3708,14 +3708,14 @@ var BaseLLM = class {
3708
3708
  * Takes a text response with component suggestions (c1:type format) and matches with available components
3709
3709
  * Also generates title, description, and intelligent follow-up questions (actions) based on the analysis
3710
3710
  * All components are placed in a default MultiComponentContainer layout
3711
- * @param textResponse - The text response containing component suggestions
3711
+ * @param analysisContent - The text response containing component suggestions
3712
3712
  * @param components - List of available components
3713
3713
  * @param apiKey - Optional API key
3714
3714
  * @param logCollector - Optional log collector
3715
3715
  * @param componentStreamCallback - Optional callback to stream primary KPI component as soon as it's identified
3716
3716
  * @returns Object containing matched components, layout title/description, and follow-up actions
3717
3717
  */
3718
- async matchComponentsFromTextResponse(textResponse, components, apiKey, logCollector) {
3718
+ async matchComponentsFromAnalysis(analysisContent, components, apiKey, logCollector, componentStreamCallback) {
3719
3719
  try {
3720
3720
  logger.debug(`[${this.getProviderName()}] Starting component matching from text response`);
3721
3721
  let availableComponentsText = "No components available";
@@ -3732,14 +3732,94 @@ var BaseLLM = class {
3732
3732
  }).join("\n\n");
3733
3733
  }
3734
3734
  const schemaDoc = schema.generateSchemaDocumentation();
3735
+ logger.file("\n=============================\nText analysis response:", analysisContent);
3735
3736
  const prompts = await promptLoader.loadPrompts("match-text-components", {
3736
- TEXT_RESPONSE: textResponse,
3737
+ ANALYSIS_CONTENT: analysisContent,
3737
3738
  AVAILABLE_COMPONENTS: availableComponentsText,
3738
3739
  SCHEMA_DOC: schemaDoc
3739
3740
  });
3740
3741
  logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
3741
3742
  logger.file("\n=============================\nmatch text components system prompt:", prompts.system);
3742
3743
  logCollector?.info("Matching components from text response...");
3744
+ let fullResponseText = "";
3745
+ let answerComponentExtracted = false;
3746
+ const answerCallback = componentStreamCallback;
3747
+ const partialCallback = answerCallback ? (chunk) => {
3748
+ fullResponseText += chunk;
3749
+ if (!answerComponentExtracted && answerCallback) {
3750
+ const hasAnswerComponentMatch = fullResponseText.match(/"hasAnswerComponent"\s*:\s*(true|false)/);
3751
+ if (!hasAnswerComponentMatch || hasAnswerComponentMatch[1] !== "true") {
3752
+ return;
3753
+ }
3754
+ const answerComponentStartMatch = fullResponseText.match(/"answerComponent"\s*:\s*\{/);
3755
+ if (!answerComponentStartMatch) {
3756
+ return;
3757
+ }
3758
+ const startPos = answerComponentStartMatch.index + answerComponentStartMatch[0].length - 1;
3759
+ let braceDepth = 0;
3760
+ let inString = false;
3761
+ let escapeNext = false;
3762
+ let endPos = -1;
3763
+ for (let i = startPos; i < fullResponseText.length; i++) {
3764
+ const char = fullResponseText[i];
3765
+ if (escapeNext) {
3766
+ escapeNext = false;
3767
+ continue;
3768
+ }
3769
+ if (char === "\\") {
3770
+ escapeNext = true;
3771
+ continue;
3772
+ }
3773
+ if (char === '"') {
3774
+ inString = !inString;
3775
+ continue;
3776
+ }
3777
+ if (!inString) {
3778
+ if (char === "{") {
3779
+ braceDepth++;
3780
+ } else if (char === "}") {
3781
+ braceDepth--;
3782
+ if (braceDepth === 0) {
3783
+ endPos = i + 1;
3784
+ break;
3785
+ }
3786
+ }
3787
+ }
3788
+ }
3789
+ if (endPos > startPos) {
3790
+ const answerComponentString = fullResponseText.substring(startPos, endPos);
3791
+ try {
3792
+ const answerComponentData = JSON.parse(answerComponentString);
3793
+ if (answerComponentData && answerComponentData.componentId) {
3794
+ const originalComponent = components.find((c) => c.id === answerComponentData.componentId);
3795
+ if (originalComponent) {
3796
+ const answerComponent = {
3797
+ ...originalComponent,
3798
+ props: {
3799
+ ...originalComponent.props,
3800
+ ...answerComponentData.props
3801
+ }
3802
+ };
3803
+ const streamTime = (/* @__PURE__ */ new Date()).toISOString();
3804
+ logger.info(`[${this.getProviderName()}] \u2713 [${streamTime}] Answer component detected in stream: ${answerComponent.name} (${answerComponent.type}) - STREAMING TO FRONTEND NOW`);
3805
+ logCollector?.info(`\u2713 Answer component: ${answerComponent.name} (${answerComponent.type}) - streaming to frontend at ${streamTime}`);
3806
+ if (answerComponentData.props?.query) {
3807
+ logCollector?.logQuery(
3808
+ "Answer component query",
3809
+ answerComponentData.props.query,
3810
+ { componentName: answerComponent.name, componentType: answerComponent.type, reasoning: answerComponentData.reasoning }
3811
+ );
3812
+ }
3813
+ answerCallback(answerComponent);
3814
+ answerComponentExtracted = true;
3815
+ }
3816
+ }
3817
+ } catch (e) {
3818
+ logger.debug(`[${this.getProviderName()}] Partial answerComponent parse failed, waiting for more data...`);
3819
+ }
3820
+ }
3821
+ }
3822
+ } : void 0;
3743
3823
  const result = await LLM.stream(
3744
3824
  {
3745
3825
  sys: prompts.system,
@@ -3749,23 +3829,54 @@ var BaseLLM = class {
3749
3829
  model: this.model,
3750
3830
  maxTokens: 3e3,
3751
3831
  temperature: 0.2,
3752
- apiKey: this.getApiKey(apiKey)
3832
+ apiKey: this.getApiKey(apiKey),
3833
+ partial: partialCallback
3753
3834
  },
3754
3835
  true
3755
3836
  // Parse as JSON
3756
3837
  );
3757
3838
  logger.debug(`[${this.getProviderName()}] Component matching response parsed successfully`);
3839
+ const componentSuggestionPattern = /c\d+:(\w+)\s*:\s*(.+)/g;
3840
+ const suggestedComponents = [];
3841
+ let match;
3842
+ while ((match = componentSuggestionPattern.exec(analysisContent)) !== null) {
3843
+ suggestedComponents.push({
3844
+ type: match[1],
3845
+ reasoning: match[2].trim()
3846
+ });
3847
+ }
3758
3848
  const matchedComponents = result.matchedComponents || [];
3759
3849
  const layoutTitle = result.layoutTitle || "Dashboard";
3760
3850
  const layoutDescription = result.layoutDescription || "Multi-component dashboard";
3851
+ logger.info(`[${this.getProviderName()}] \u{1F4CA} Component Suggestions from Text Analysis: ${suggestedComponents.length}`);
3852
+ suggestedComponents.forEach((comp, idx) => {
3853
+ logger.info(`[${this.getProviderName()}] c${idx + 1}: ${comp.type} - ${comp.reasoning}`);
3854
+ });
3855
+ logger.info(`[${this.getProviderName()}] \u{1F4E6} Matched Components from LLM: ${matchedComponents.length}`);
3856
+ matchedComponents.forEach((comp, idx) => {
3857
+ logger.info(`[${this.getProviderName()}] ${idx + 1}. ${comp.componentType} (${comp.componentName}) - ${comp.originalSuggestion || "N/A"}`);
3858
+ });
3859
+ if (suggestedComponents.length !== matchedComponents.length) {
3860
+ logger.warn(`[${this.getProviderName()}] \u26A0\uFE0F MISMATCH: Text suggested ${suggestedComponents.length} components, but LLM matched ${matchedComponents.length}`);
3861
+ }
3862
+ logger.file("\n=============================\nFull LLM response:", JSON.stringify(result, null, 2));
3761
3863
  const rawActions = result.actions || [];
3762
3864
  const actions = convertQuestionsToActions(rawActions);
3763
3865
  logger.info(`[${this.getProviderName()}] Matched ${matchedComponents.length} components from text response`);
3764
3866
  logger.info(`[${this.getProviderName()}] Layout title: "${layoutTitle}"`);
3765
3867
  logger.info(`[${this.getProviderName()}] Layout description: "${layoutDescription}"`);
3766
3868
  logger.info(`[${this.getProviderName()}] Generated ${actions.length} follow-up actions`);
3869
+ if (suggestedComponents.length > 0) {
3870
+ logCollector?.info(`\u{1F4DD} Text Analysis suggested ${suggestedComponents.length} dashboard components:`);
3871
+ suggestedComponents.forEach((comp, idx) => {
3872
+ logCollector?.info(` c${idx + 1}: ${comp.type} - ${comp.reasoning}`);
3873
+ });
3874
+ }
3767
3875
  if (matchedComponents.length > 0) {
3768
- logCollector?.info(`Matched ${matchedComponents.length} components for visualization`);
3876
+ logCollector?.info(`\u{1F4E6} Matched ${matchedComponents.length} components for dashboard`);
3877
+ if (suggestedComponents.length !== matchedComponents.length) {
3878
+ logCollector?.warn(`\u26A0\uFE0F Component count mismatch: Suggested ${suggestedComponents.length}, but matched ${matchedComponents.length}`);
3879
+ }
3769
3880
  logCollector?.info(`Dashboard: "${layoutTitle}"`);
3770
3881
  matchedComponents.forEach((comp, idx) => {
3771
3882
  logCollector?.info(` ${idx + 1}. ${comp.componentName} (${comp.componentType}): ${comp.reasoning}`);
@@ -4240,11 +4351,17 @@ ${errorMsg}
4240
4351
  let actions = [];
4241
4352
  if (components && components.length > 0) {
4242
4353
  logger.info(`[${this.getProviderName()}] Matching components from text response...`);
4243
- const matchResult = await this.matchComponentsFromTextResponse(
4354
+ const componentStreamCallback = wrappedStreamCallback ? (component) => {
4355
+ const answerMarker = `__ANSWER_COMPONENT_START__${JSON.stringify(component)}__ANSWER_COMPONENT_END__`;
4356
+ wrappedStreamCallback(answerMarker);
4357
+ logger.info(`[${this.getProviderName()}] Streamed answer component to frontend: ${component.name} (${component.type})`);
4358
+ } : void 0;
4359
+ const matchResult = await this.matchComponentsFromAnalysis(
4244
4360
  textResponse,
4245
4361
  components,
4246
4362
  apiKey,
4247
- logCollector
4363
+ logCollector,
4364
+ componentStreamCallback
4248
4365
  );
4249
4366
  matchedComponents = matchResult.components;
4250
4367
  layoutTitle = matchResult.layoutTitle;
@@ -5119,7 +5236,6 @@ function sendDataResponse4(id, res, sendMessage, clientId) {
5119
5236
  ...res
5120
5237
  }
5121
5238
  };
5122
- logger.info("sending user prompt response", response);
5123
5239
  sendMessage(response);
5124
5240
  }
5125
5241