@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.js CHANGED
@@ -3748,14 +3748,14 @@ var BaseLLM = class {
3748
3748
  * Takes a text response with component suggestions (c1:type format) and matches with available components
3749
3749
  * Also generates title, description, and intelligent follow-up questions (actions) based on the analysis
3750
3750
  * All components are placed in a default MultiComponentContainer layout
3751
- * @param textResponse - The text response containing component suggestions
3751
+ * @param analysisContent - The text response containing component suggestions
3752
3752
  * @param components - List of available components
3753
3753
  * @param apiKey - Optional API key
3754
3754
  * @param logCollector - Optional log collector
3755
3755
  * @param componentStreamCallback - Optional callback to stream primary KPI component as soon as it's identified
3756
3756
  * @returns Object containing matched components, layout title/description, and follow-up actions
3757
3757
  */
3758
- async matchComponentsFromTextResponse(textResponse, components, apiKey, logCollector) {
3758
+ async matchComponentsFromAnalysis(analysisContent, components, apiKey, logCollector, componentStreamCallback) {
3759
3759
  try {
3760
3760
  logger.debug(`[${this.getProviderName()}] Starting component matching from text response`);
3761
3761
  let availableComponentsText = "No components available";
@@ -3772,14 +3772,94 @@ var BaseLLM = class {
3772
3772
  }).join("\n\n");
3773
3773
  }
3774
3774
  const schemaDoc = schema.generateSchemaDocumentation();
3775
+ logger.file("\n=============================\nText analysis response:", analysisContent);
3775
3776
  const prompts = await promptLoader.loadPrompts("match-text-components", {
3776
- TEXT_RESPONSE: textResponse,
3777
+ ANALYSIS_CONTENT: analysisContent,
3777
3778
  AVAILABLE_COMPONENTS: availableComponentsText,
3778
3779
  SCHEMA_DOC: schemaDoc
3779
3780
  });
3780
3781
  logger.debug(`[${this.getProviderName()}] Loaded match-text-components prompts`);
3781
3782
  logger.file("\n=============================\nmatch text components system prompt:", prompts.system);
3782
3783
  logCollector?.info("Matching components from text response...");
3784
+ let fullResponseText = "";
3785
+ let answerComponentExtracted = false;
3786
+ const answerCallback = componentStreamCallback;
3787
+ const partialCallback = answerCallback ? (chunk) => {
3788
+ fullResponseText += chunk;
3789
+ if (!answerComponentExtracted && answerCallback) {
3790
+ const hasAnswerComponentMatch = fullResponseText.match(/"hasAnswerComponent"\s*:\s*(true|false)/);
3791
+ if (!hasAnswerComponentMatch || hasAnswerComponentMatch[1] !== "true") {
3792
+ return;
3793
+ }
3794
+ const answerComponentStartMatch = fullResponseText.match(/"answerComponent"\s*:\s*\{/);
3795
+ if (!answerComponentStartMatch) {
3796
+ return;
3797
+ }
3798
+ const startPos = answerComponentStartMatch.index + answerComponentStartMatch[0].length - 1;
3799
+ let braceDepth = 0;
3800
+ let inString = false;
3801
+ let escapeNext = false;
3802
+ let endPos = -1;
3803
+ for (let i = startPos; i < fullResponseText.length; i++) {
3804
+ const char = fullResponseText[i];
3805
+ if (escapeNext) {
3806
+ escapeNext = false;
3807
+ continue;
3808
+ }
3809
+ if (char === "\\") {
3810
+ escapeNext = true;
3811
+ continue;
3812
+ }
3813
+ if (char === '"') {
3814
+ inString = !inString;
3815
+ continue;
3816
+ }
3817
+ if (!inString) {
3818
+ if (char === "{") {
3819
+ braceDepth++;
3820
+ } else if (char === "}") {
3821
+ braceDepth--;
3822
+ if (braceDepth === 0) {
3823
+ endPos = i + 1;
3824
+ break;
3825
+ }
3826
+ }
3827
+ }
3828
+ }
3829
+ if (endPos > startPos) {
3830
+ const answerComponentString = fullResponseText.substring(startPos, endPos);
3831
+ try {
3832
+ const answerComponentData = JSON.parse(answerComponentString);
3833
+ if (answerComponentData && answerComponentData.componentId) {
3834
+ const originalComponent = components.find((c) => c.id === answerComponentData.componentId);
3835
+ if (originalComponent) {
3836
+ const answerComponent = {
3837
+ ...originalComponent,
3838
+ props: {
3839
+ ...originalComponent.props,
3840
+ ...answerComponentData.props
3841
+ }
3842
+ };
3843
+ const streamTime = (/* @__PURE__ */ new Date()).toISOString();
3844
+ logger.info(`[${this.getProviderName()}] \u2713 [${streamTime}] Answer component detected in stream: ${answerComponent.name} (${answerComponent.type}) - STREAMING TO FRONTEND NOW`);
3845
+ logCollector?.info(`\u2713 Answer component: ${answerComponent.name} (${answerComponent.type}) - streaming to frontend at ${streamTime}`);
3846
+ if (answerComponentData.props?.query) {
3847
+ logCollector?.logQuery(
3848
+ "Answer component query",
3849
+ answerComponentData.props.query,
3850
+ { componentName: answerComponent.name, componentType: answerComponent.type, reasoning: answerComponentData.reasoning }
3851
+ );
3852
+ }
3853
+ answerCallback(answerComponent);
3854
+ answerComponentExtracted = true;
3855
+ }
3856
+ }
3857
+ } catch (e) {
3858
+ logger.debug(`[${this.getProviderName()}] Partial answerComponent parse failed, waiting for more data...`);
3859
+ }
3860
+ }
3861
+ }
3862
+ } : void 0;
3783
3863
  const result = await LLM.stream(
3784
3864
  {
3785
3865
  sys: prompts.system,
@@ -3789,23 +3869,54 @@ var BaseLLM = class {
3789
3869
  model: this.model,
3790
3870
  maxTokens: 3e3,
3791
3871
  temperature: 0.2,
3792
- apiKey: this.getApiKey(apiKey)
3872
+ apiKey: this.getApiKey(apiKey),
3873
+ partial: partialCallback
3793
3874
  },
3794
3875
  true
3795
3876
  // Parse as JSON
3796
3877
  );
3797
3878
  logger.debug(`[${this.getProviderName()}] Component matching response parsed successfully`);
3879
+ const componentSuggestionPattern = /c\d+:(\w+)\s*:\s*(.+)/g;
3880
+ const suggestedComponents = [];
3881
+ let match;
3882
+ while ((match = componentSuggestionPattern.exec(analysisContent)) !== null) {
3883
+ suggestedComponents.push({
3884
+ type: match[1],
3885
+ reasoning: match[2].trim()
3886
+ });
3887
+ }
3798
3888
  const matchedComponents = result.matchedComponents || [];
3799
3889
  const layoutTitle = result.layoutTitle || "Dashboard";
3800
3890
  const layoutDescription = result.layoutDescription || "Multi-component dashboard";
3891
+ logger.info(`[${this.getProviderName()}] \u{1F4CA} Component Suggestions from Text Analysis: ${suggestedComponents.length}`);
3892
+ suggestedComponents.forEach((comp, idx) => {
3893
+ logger.info(`[${this.getProviderName()}] c${idx + 1}: ${comp.type} - ${comp.reasoning}`);
3894
+ });
3895
+ logger.info(`[${this.getProviderName()}] \u{1F4E6} Matched Components from LLM: ${matchedComponents.length}`);
3896
+ matchedComponents.forEach((comp, idx) => {
3897
+ logger.info(`[${this.getProviderName()}] ${idx + 1}. ${comp.componentType} (${comp.componentName}) - ${comp.originalSuggestion || "N/A"}`);
3898
+ });
3899
+ if (suggestedComponents.length !== matchedComponents.length) {
3900
+ logger.warn(`[${this.getProviderName()}] \u26A0\uFE0F MISMATCH: Text suggested ${suggestedComponents.length} components, but LLM matched ${matchedComponents.length}`);
3901
+ }
3902
+ logger.file("\n=============================\nFull LLM response:", JSON.stringify(result, null, 2));
3801
3903
  const rawActions = result.actions || [];
3802
3904
  const actions = convertQuestionsToActions(rawActions);
3803
3905
  logger.info(`[${this.getProviderName()}] Matched ${matchedComponents.length} components from text response`);
3804
3906
  logger.info(`[${this.getProviderName()}] Layout title: "${layoutTitle}"`);
3805
3907
  logger.info(`[${this.getProviderName()}] Layout description: "${layoutDescription}"`);
3806
3908
  logger.info(`[${this.getProviderName()}] Generated ${actions.length} follow-up actions`);
3909
+ if (suggestedComponents.length > 0) {
3910
+ logCollector?.info(`\u{1F4DD} Text Analysis suggested ${suggestedComponents.length} dashboard components:`);
3911
+ suggestedComponents.forEach((comp, idx) => {
3912
+ logCollector?.info(` c${idx + 1}: ${comp.type} - ${comp.reasoning}`);
3913
+ });
3914
+ }
3807
3915
  if (matchedComponents.length > 0) {
3808
- logCollector?.info(`Matched ${matchedComponents.length} components for visualization`);
3916
+ logCollector?.info(`\u{1F4E6} Matched ${matchedComponents.length} components for dashboard`);
3917
+ if (suggestedComponents.length !== matchedComponents.length) {
3918
+ logCollector?.warn(`\u26A0\uFE0F Component count mismatch: Suggested ${suggestedComponents.length}, but matched ${matchedComponents.length}`);
3919
+ }
3809
3920
  logCollector?.info(`Dashboard: "${layoutTitle}"`);
3810
3921
  matchedComponents.forEach((comp, idx) => {
3811
3922
  logCollector?.info(` ${idx + 1}. ${comp.componentName} (${comp.componentType}): ${comp.reasoning}`);
@@ -4280,11 +4391,17 @@ ${errorMsg}
4280
4391
  let actions = [];
4281
4392
  if (components && components.length > 0) {
4282
4393
  logger.info(`[${this.getProviderName()}] Matching components from text response...`);
4283
- const matchResult = await this.matchComponentsFromTextResponse(
4394
+ const componentStreamCallback = wrappedStreamCallback ? (component) => {
4395
+ const answerMarker = `__ANSWER_COMPONENT_START__${JSON.stringify(component)}__ANSWER_COMPONENT_END__`;
4396
+ wrappedStreamCallback(answerMarker);
4397
+ logger.info(`[${this.getProviderName()}] Streamed answer component to frontend: ${component.name} (${component.type})`);
4398
+ } : void 0;
4399
+ const matchResult = await this.matchComponentsFromAnalysis(
4284
4400
  textResponse,
4285
4401
  components,
4286
4402
  apiKey,
4287
- logCollector
4403
+ logCollector,
4404
+ componentStreamCallback
4288
4405
  );
4289
4406
  matchedComponents = matchResult.components;
4290
4407
  layoutTitle = matchResult.layoutTitle;
@@ -5159,7 +5276,6 @@ function sendDataResponse4(id, res, sendMessage, clientId) {
5159
5276
  ...res
5160
5277
  }
5161
5278
  };
5162
- logger.info("sending user prompt response", response);
5163
5279
  sendMessage(response);
5164
5280
  }
5165
5281