@superatomai/sdk-node 0.0.36-mds → 0.0.37-mds

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
@@ -10724,6 +10724,77 @@ var get_agent_user_response = async (prompt, components, anthropicApiKey, groqAp
10724
10724
  }
10725
10725
  };
10726
10726
 
10727
+ // src/utils/analytics-client.ts
10728
+ var AnalyticsClient = class {
10729
+ constructor() {
10730
+ this.apiUrl = null;
10731
+ this.orgId = null;
10732
+ this.enabled = true;
10733
+ this.initialized = false;
10734
+ }
10735
+ init() {
10736
+ if (this.initialized) return;
10737
+ this.initialized = true;
10738
+ this.apiUrl = process.env.SA_API_URL || null;
10739
+ this.orgId = process.env.SA_ORG_ID || null;
10740
+ this.enabled = process.env.SA_ANALYTICS_ENABLED !== "false";
10741
+ if (!this.apiUrl) {
10742
+ if (this.enabled) {
10743
+ logger.warn("[Analytics] Disabled \u2014 SA_API_URL not configured");
10744
+ }
10745
+ this.enabled = false;
10746
+ }
10747
+ }
10748
+ /**
10749
+ * Track a chat analytics event. Fire-and-forget — never blocks or throws.
10750
+ */
10751
+ async track(event) {
10752
+ this.init();
10753
+ if (!this.enabled) return;
10754
+ try {
10755
+ const response = await fetch(`${this.apiUrl}/analytics/chat`, {
10756
+ method: "POST",
10757
+ headers: {
10758
+ "Content-Type": "application/json"
10759
+ },
10760
+ body: JSON.stringify(event)
10761
+ });
10762
+ if (!response.ok) {
10763
+ const errorText = await response.text().catch(() => "unknown");
10764
+ logger.warn(`[Analytics] Failed to track event: ${response.status} ${errorText}`);
10765
+ }
10766
+ } catch (err) {
10767
+ logger.warn(`[Analytics] Failed to send event: ${err instanceof Error ? err.message : String(err)}`);
10768
+ }
10769
+ }
10770
+ /**
10771
+ * Build a ChatAnalyticsEvent from the available request context.
10772
+ * Reads session stats from llmUsageLogger automatically.
10773
+ */
10774
+ buildEvent(params) {
10775
+ this.init();
10776
+ const stats = llmUsageLogger.getSessionStats();
10777
+ return {
10778
+ userId: params.userId,
10779
+ orgId: this.orgId || void 0,
10780
+ projectId: params.projectId,
10781
+ threadId: params.threadId,
10782
+ messageIndex: params.messageIndex,
10783
+ question: params.question,
10784
+ sourcesUsed: params.sourcesUsed,
10785
+ sqlGenerated: params.sqlGenerated,
10786
+ model: params.model,
10787
+ inputTokens: stats.totalInputTokens,
10788
+ outputTokens: stats.totalOutputTokens,
10789
+ cost: stats.totalCostUSD.toFixed(6),
10790
+ latencyMs: params.latencyMs,
10791
+ status: params.success ? "success" : "error",
10792
+ errorMessage: params.errorMessage
10793
+ };
10794
+ }
10795
+ };
10796
+ var analyticsClient = new AnalyticsClient();
10797
+
10727
10798
  // src/utils/conversation-saver.ts
10728
10799
  function transformUIBlockForDB(uiblock, userPrompt, uiBlockId) {
10729
10800
  const component = uiblock?.generatedComponentMetadata && Object.keys(uiblock.generatedComponentMetadata).length > 0 ? uiblock.generatedComponentMetadata : null;
@@ -10886,6 +10957,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
10886
10957
  thread = threadManager.createThread(threadId);
10887
10958
  logger.info(`Created new thread: ${threadId}`);
10888
10959
  }
10960
+ const requestStartTime = Date.now();
10889
10961
  logger.info(`Starting user prompt request with ${components.length} components`);
10890
10962
  const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
10891
10963
  const responseMode = payload.responseMode || "component";
@@ -10943,6 +11015,23 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
10943
11015
  });
10944
11016
  userPromptErrorLogger.writeSummary();
10945
11017
  llmUsageLogger.logSessionSummary(`FAILED: ${prompt?.substring(0, 30)}`);
11018
+ if (userId) {
11019
+ const latencyMs = Date.now() - requestStartTime;
11020
+ const model = mainAgentModel || "unknown";
11021
+ const event = analyticsClient.buildEvent({
11022
+ userId,
11023
+ projectId: process.env.SUPERATOM_PROJECT_ID || "",
11024
+ threadId,
11025
+ messageIndex: 0,
11026
+ question: prompt,
11027
+ success: false,
11028
+ latencyMs,
11029
+ model,
11030
+ errorMessage: userResponse.errors.join("; ")
11031
+ });
11032
+ analyticsClient.track(event).catch(() => {
11033
+ });
11034
+ }
10946
11035
  return {
10947
11036
  success: false,
10948
11037
  data: userResponse.data,
@@ -11019,6 +11108,42 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
11019
11108
  }
11020
11109
  }
11021
11110
  llmUsageLogger.logSessionSummary(prompt?.substring(0, 50));
11111
+ if (userId) {
11112
+ const latencyMs = Date.now() - requestStartTime;
11113
+ const model = mainAgentModel || "unknown";
11114
+ const componentConfig = userResponse.data?.component?.props?.config;
11115
+ const queryMap = componentConfig?._queryMap || {};
11116
+ const sqlStatements = Object.values(queryMap).filter((v) => typeof v === "string");
11117
+ const childComponents = componentConfig?.components || [];
11118
+ const sourceSet = /* @__PURE__ */ new Map();
11119
+ for (const child of childComponents) {
11120
+ const toolId = child?.props?.externalTool?.toolId;
11121
+ const toolName = child?.props?.externalTool?.name;
11122
+ if (toolId && !sourceSet.has(toolId)) {
11123
+ sourceSet.set(toolId, {
11124
+ sourceId: toolId,
11125
+ sourceName: toolName || toolId,
11126
+ sourceType: toolId.split("-")[0] || ""
11127
+ // e.g. "postgres" from "postgres-xxx_query"
11128
+ });
11129
+ }
11130
+ }
11131
+ const sourcesUsed = Array.from(sourceSet.values());
11132
+ const event = analyticsClient.buildEvent({
11133
+ userId,
11134
+ projectId: process.env.SUPERATOM_PROJECT_ID || "",
11135
+ threadId,
11136
+ messageIndex: thread.getUIBlockCount(),
11137
+ question: prompt,
11138
+ success: true,
11139
+ latencyMs,
11140
+ model,
11141
+ sourcesUsed: sourcesUsed.length > 0 ? sourcesUsed : void 0,
11142
+ sqlGenerated: sqlStatements.length > 0 ? sqlStatements.join(";\n") : void 0
11143
+ });
11144
+ analyticsClient.track(event).catch(() => {
11145
+ });
11146
+ }
11022
11147
  return {
11023
11148
  success: userResponse.success,
11024
11149
  data: userResponse.data,