@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.mjs CHANGED
@@ -10664,6 +10664,77 @@ var get_agent_user_response = async (prompt, components, anthropicApiKey, groqAp
10664
10664
  }
10665
10665
  };
10666
10666
 
10667
+ // src/utils/analytics-client.ts
10668
+ var AnalyticsClient = class {
10669
+ constructor() {
10670
+ this.apiUrl = null;
10671
+ this.orgId = null;
10672
+ this.enabled = true;
10673
+ this.initialized = false;
10674
+ }
10675
+ init() {
10676
+ if (this.initialized) return;
10677
+ this.initialized = true;
10678
+ this.apiUrl = process.env.SA_API_URL || null;
10679
+ this.orgId = process.env.SA_ORG_ID || null;
10680
+ this.enabled = process.env.SA_ANALYTICS_ENABLED !== "false";
10681
+ if (!this.apiUrl) {
10682
+ if (this.enabled) {
10683
+ logger.warn("[Analytics] Disabled \u2014 SA_API_URL not configured");
10684
+ }
10685
+ this.enabled = false;
10686
+ }
10687
+ }
10688
+ /**
10689
+ * Track a chat analytics event. Fire-and-forget — never blocks or throws.
10690
+ */
10691
+ async track(event) {
10692
+ this.init();
10693
+ if (!this.enabled) return;
10694
+ try {
10695
+ const response = await fetch(`${this.apiUrl}/analytics/chat`, {
10696
+ method: "POST",
10697
+ headers: {
10698
+ "Content-Type": "application/json"
10699
+ },
10700
+ body: JSON.stringify(event)
10701
+ });
10702
+ if (!response.ok) {
10703
+ const errorText = await response.text().catch(() => "unknown");
10704
+ logger.warn(`[Analytics] Failed to track event: ${response.status} ${errorText}`);
10705
+ }
10706
+ } catch (err) {
10707
+ logger.warn(`[Analytics] Failed to send event: ${err instanceof Error ? err.message : String(err)}`);
10708
+ }
10709
+ }
10710
+ /**
10711
+ * Build a ChatAnalyticsEvent from the available request context.
10712
+ * Reads session stats from llmUsageLogger automatically.
10713
+ */
10714
+ buildEvent(params) {
10715
+ this.init();
10716
+ const stats = llmUsageLogger.getSessionStats();
10717
+ return {
10718
+ userId: params.userId,
10719
+ orgId: this.orgId || void 0,
10720
+ projectId: params.projectId,
10721
+ threadId: params.threadId,
10722
+ messageIndex: params.messageIndex,
10723
+ question: params.question,
10724
+ sourcesUsed: params.sourcesUsed,
10725
+ sqlGenerated: params.sqlGenerated,
10726
+ model: params.model,
10727
+ inputTokens: stats.totalInputTokens,
10728
+ outputTokens: stats.totalOutputTokens,
10729
+ cost: stats.totalCostUSD.toFixed(6),
10730
+ latencyMs: params.latencyMs,
10731
+ status: params.success ? "success" : "error",
10732
+ errorMessage: params.errorMessage
10733
+ };
10734
+ }
10735
+ };
10736
+ var analyticsClient = new AnalyticsClient();
10737
+
10667
10738
  // src/utils/conversation-saver.ts
10668
10739
  function transformUIBlockForDB(uiblock, userPrompt, uiBlockId) {
10669
10740
  const component = uiblock?.generatedComponentMetadata && Object.keys(uiblock.generatedComponentMetadata).length > 0 ? uiblock.generatedComponentMetadata : null;
@@ -10826,6 +10897,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
10826
10897
  thread = threadManager.createThread(threadId);
10827
10898
  logger.info(`Created new thread: ${threadId}`);
10828
10899
  }
10900
+ const requestStartTime = Date.now();
10829
10901
  logger.info(`Starting user prompt request with ${components.length} components`);
10830
10902
  const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
10831
10903
  const responseMode = payload.responseMode || "component";
@@ -10883,6 +10955,23 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
10883
10955
  });
10884
10956
  userPromptErrorLogger.writeSummary();
10885
10957
  llmUsageLogger.logSessionSummary(`FAILED: ${prompt?.substring(0, 30)}`);
10958
+ if (userId) {
10959
+ const latencyMs = Date.now() - requestStartTime;
10960
+ const model = mainAgentModel || "unknown";
10961
+ const event = analyticsClient.buildEvent({
10962
+ userId,
10963
+ projectId: process.env.SUPERATOM_PROJECT_ID || "",
10964
+ threadId,
10965
+ messageIndex: 0,
10966
+ question: prompt,
10967
+ success: false,
10968
+ latencyMs,
10969
+ model,
10970
+ errorMessage: userResponse.errors.join("; ")
10971
+ });
10972
+ analyticsClient.track(event).catch(() => {
10973
+ });
10974
+ }
10886
10975
  return {
10887
10976
  success: false,
10888
10977
  data: userResponse.data,
@@ -10959,6 +11048,42 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
10959
11048
  }
10960
11049
  }
10961
11050
  llmUsageLogger.logSessionSummary(prompt?.substring(0, 50));
11051
+ if (userId) {
11052
+ const latencyMs = Date.now() - requestStartTime;
11053
+ const model = mainAgentModel || "unknown";
11054
+ const componentConfig = userResponse.data?.component?.props?.config;
11055
+ const queryMap = componentConfig?._queryMap || {};
11056
+ const sqlStatements = Object.values(queryMap).filter((v) => typeof v === "string");
11057
+ const childComponents = componentConfig?.components || [];
11058
+ const sourceSet = /* @__PURE__ */ new Map();
11059
+ for (const child of childComponents) {
11060
+ const toolId = child?.props?.externalTool?.toolId;
11061
+ const toolName = child?.props?.externalTool?.name;
11062
+ if (toolId && !sourceSet.has(toolId)) {
11063
+ sourceSet.set(toolId, {
11064
+ sourceId: toolId,
11065
+ sourceName: toolName || toolId,
11066
+ sourceType: toolId.split("-")[0] || ""
11067
+ // e.g. "postgres" from "postgres-xxx_query"
11068
+ });
11069
+ }
11070
+ }
11071
+ const sourcesUsed = Array.from(sourceSet.values());
11072
+ const event = analyticsClient.buildEvent({
11073
+ userId,
11074
+ projectId: process.env.SUPERATOM_PROJECT_ID || "",
11075
+ threadId,
11076
+ messageIndex: thread.getUIBlockCount(),
11077
+ question: prompt,
11078
+ success: true,
11079
+ latencyMs,
11080
+ model,
11081
+ sourcesUsed: sourcesUsed.length > 0 ? sourcesUsed : void 0,
11082
+ sqlGenerated: sqlStatements.length > 0 ? sqlStatements.join(";\n") : void 0
11083
+ });
11084
+ analyticsClient.track(event).catch(() => {
11085
+ });
11086
+ }
10962
11087
  return {
10963
11088
  success: userResponse.success,
10964
11089
  data: userResponse.data,