@fallom/trace 0.1.12 → 0.2.0

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
@@ -1,25 +1,19 @@
1
1
  import {
2
2
  __export,
3
3
  init,
4
- prompts_exports
5
- } from "./chunk-6MSTRIK4.mjs";
4
+ models_exports
5
+ } from "./chunk-W6M2RQ3W.mjs";
6
6
 
7
7
  // src/trace.ts
8
8
  var trace_exports = {};
9
9
  __export(trace_exports, {
10
- clearSession: () => clearSession,
11
- getSession: () => getSession,
10
+ FallomSession: () => FallomSession,
12
11
  init: () => init2,
13
- runWithSession: () => runWithSession,
14
- setSession: () => setSession,
15
- shutdown: () => shutdown,
16
- span: () => span,
17
- wrapAISDK: () => wrapAISDK,
18
- wrapAnthropic: () => wrapAnthropic,
19
- wrapGoogleAI: () => wrapGoogleAI,
20
- wrapMastraAgent: () => wrapMastraAgent,
21
- wrapOpenAI: () => wrapOpenAI
12
+ session: () => session,
13
+ shutdown: () => shutdown
22
14
  });
15
+
16
+ // src/trace/core.ts
23
17
  import { AsyncLocalStorage } from "async_hooks";
24
18
  import { NodeSDK } from "@opentelemetry/sdk-node";
25
19
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
@@ -621,9 +615,9 @@ var Resource = (
621
615
  })()
622
616
  );
623
617
 
624
- // src/trace.ts
625
- var sessionStorage = new AsyncLocalStorage();
626
- var fallbackSession = null;
618
+ // src/trace/core.ts
619
+ var traceContextStorage = new AsyncLocalStorage();
620
+ var fallbackTraceContext = null;
627
621
  var apiKey = null;
628
622
  var baseUrl = "https://traces.fallom.com";
629
623
  var initialized = false;
@@ -633,28 +627,27 @@ var sdk = null;
633
627
  function log(...args) {
634
628
  if (debugMode) console.log("[Fallom]", ...args);
635
629
  }
630
+ function getTraceContextStorage() {
631
+ return traceContextStorage;
632
+ }
633
+ function getFallbackTraceContext() {
634
+ return fallbackTraceContext;
635
+ }
636
+ function isInitialized() {
637
+ return initialized;
638
+ }
639
+ function shouldCaptureContent() {
640
+ return captureContent;
641
+ }
642
+ function isDebugMode() {
643
+ return debugMode;
644
+ }
636
645
  var fallomSpanProcessor = {
637
- onStart(span2, _parentContext) {
638
- log("\u{1F4CD} Span started:", span2.name || "unknown");
639
- const ctx = sessionStorage.getStore() || fallbackSession;
640
- if (ctx) {
641
- span2.setAttribute("fallom.config_key", ctx.configKey);
642
- span2.setAttribute("fallom.session_id", ctx.sessionId);
643
- if (ctx.customerId) {
644
- span2.setAttribute("fallom.customer_id", ctx.customerId);
645
- }
646
- log(
647
- " Added session context:",
648
- ctx.configKey,
649
- ctx.sessionId,
650
- ctx.customerId
651
- );
652
- } else {
653
- log(" No session context available");
654
- }
646
+ onStart(span, _parentContext) {
647
+ log("\u{1F4CD} Span started:", span.name || "unknown");
655
648
  },
656
- onEnd(span2) {
657
- log("\u2705 Span ended:", span2.name, "duration:", span2.duration);
649
+ onEnd(span) {
650
+ log("\u2705 Span ended:", span.name, "duration:", span.duration);
658
651
  },
659
652
  shutdown() {
660
653
  return Promise.resolve();
@@ -663,47 +656,6 @@ var fallomSpanProcessor = {
663
656
  return Promise.resolve();
664
657
  }
665
658
  };
666
- async function init2(options = {}) {
667
- if (initialized) return;
668
- debugMode = options.debug ?? false;
669
- log("\u{1F680} Initializing Fallom tracing...");
670
- apiKey = options.apiKey || process.env.FALLOM_API_KEY || null;
671
- baseUrl = options.baseUrl || process.env.FALLOM_TRACES_URL || process.env.FALLOM_BASE_URL || "https://traces.fallom.com";
672
- const envCapture = process.env.FALLOM_CAPTURE_CONTENT?.toLowerCase();
673
- if (envCapture === "false" || envCapture === "0" || envCapture === "no") {
674
- captureContent = false;
675
- } else {
676
- captureContent = options.captureContent ?? true;
677
- }
678
- if (!apiKey) {
679
- throw new Error(
680
- "No API key provided. Set FALLOM_API_KEY environment variable or pass apiKey parameter."
681
- );
682
- }
683
- initialized = true;
684
- log("\u{1F4E1} Exporter URL:", `${baseUrl}/v1/traces`);
685
- const exporter = new OTLPTraceExporter({
686
- url: `${baseUrl}/v1/traces`,
687
- headers: {
688
- Authorization: `Bearer ${apiKey}`
689
- }
690
- });
691
- const instrumentations = await getInstrumentations();
692
- log("\u{1F527} Loaded instrumentations:", instrumentations.length);
693
- sdk = new NodeSDK({
694
- resource: new Resource({
695
- "service.name": "fallom-traced-app"
696
- }),
697
- traceExporter: exporter,
698
- spanProcessor: fallomSpanProcessor,
699
- instrumentations
700
- });
701
- sdk.start();
702
- log("\u2705 SDK started");
703
- process.on("SIGTERM", () => {
704
- sdk?.shutdown().catch(console.error);
705
- });
706
- }
707
659
  async function getInstrumentations() {
708
660
  const instrumentations = [];
709
661
  await tryAddInstrumentation(
@@ -758,75 +710,90 @@ async function tryAddInstrumentation(instrumentations, pkg, className) {
758
710
  Object.keys(mod)
759
711
  );
760
712
  }
761
- } catch (e) {
713
+ } catch {
762
714
  log(` \u274C ${pkg} not installed`);
763
715
  }
764
716
  }
765
- function setSession(configKey, sessionId, customerId) {
766
- const store = sessionStorage.getStore();
767
- if (store) {
768
- store.configKey = configKey;
769
- store.sessionId = sessionId;
770
- store.customerId = customerId;
771
- }
772
- fallbackSession = { configKey, sessionId, customerId };
773
- }
774
- function runWithSession(configKey, sessionId, customerIdOrFn, fn) {
775
- if (typeof customerIdOrFn === "function") {
776
- return sessionStorage.run({ configKey, sessionId }, customerIdOrFn);
777
- }
778
- return sessionStorage.run(
779
- { configKey, sessionId, customerId: customerIdOrFn },
780
- fn
781
- );
782
- }
783
- function getSession() {
784
- return sessionStorage.getStore() || fallbackSession || void 0;
785
- }
786
- function clearSession() {
787
- fallbackSession = null;
788
- }
789
- function span(data, options = {}) {
790
- if (!initialized) {
791
- throw new Error("Fallom not initialized. Call trace.init() first.");
717
+ async function init2(options = {}) {
718
+ if (initialized) return;
719
+ debugMode = options.debug ?? false;
720
+ log("\u{1F680} Initializing Fallom tracing...");
721
+ apiKey = options.apiKey || process.env.FALLOM_API_KEY || null;
722
+ baseUrl = options.baseUrl || process.env.FALLOM_TRACES_URL || process.env.FALLOM_BASE_URL || "https://traces.fallom.com";
723
+ const envCapture = process.env.FALLOM_CAPTURE_CONTENT?.toLowerCase();
724
+ if (envCapture === "false" || envCapture === "0" || envCapture === "no") {
725
+ captureContent = false;
726
+ } else {
727
+ captureContent = options.captureContent ?? true;
792
728
  }
793
- const ctx = sessionStorage.getStore() || fallbackSession;
794
- const configKey = options.configKey || ctx?.configKey;
795
- const sessionId = options.sessionId || ctx?.sessionId;
796
- if (!configKey || !sessionId) {
729
+ if (!apiKey) {
797
730
  throw new Error(
798
- "No session context. Either call setSession() first, or pass configKey and sessionId explicitly."
731
+ "No API key provided. Set FALLOM_API_KEY environment variable or pass apiKey parameter."
799
732
  );
800
733
  }
801
- sendSpan(configKey, sessionId, data).catch(() => {
734
+ initialized = true;
735
+ log("\u{1F4E1} Exporter URL:", `${baseUrl}/v1/traces`);
736
+ const exporter = new OTLPTraceExporter({
737
+ url: `${baseUrl}/v1/traces`,
738
+ headers: {
739
+ Authorization: `Bearer ${apiKey}`
740
+ }
741
+ });
742
+ const instrumentations = await getInstrumentations();
743
+ log("\u{1F527} Loaded instrumentations:", instrumentations.length);
744
+ sdk = new NodeSDK({
745
+ resource: new Resource({
746
+ "service.name": "fallom-traced-app"
747
+ }),
748
+ traceExporter: exporter,
749
+ spanProcessor: fallomSpanProcessor,
750
+ instrumentations
751
+ });
752
+ sdk.start();
753
+ log("\u2705 SDK started");
754
+ process.on("SIGTERM", () => {
755
+ sdk?.shutdown().catch(console.error);
802
756
  });
803
757
  }
804
- async function sendSpan(configKey, sessionId, data) {
758
+ async function shutdown() {
759
+ if (sdk) {
760
+ await sdk.shutdown();
761
+ initialized = false;
762
+ }
763
+ }
764
+ async function sendTrace(trace) {
765
+ const url = `${baseUrl}/v1/traces`;
766
+ log("\u{1F4E4} Sending trace to:", url);
767
+ log(" Session:", trace.session_id, "Config:", trace.config_key);
805
768
  try {
806
769
  const controller = new AbortController();
807
770
  const timeoutId = setTimeout(() => controller.abort(), 5e3);
808
- await fetch(`${baseUrl}/spans`, {
771
+ const response = await fetch(url, {
809
772
  method: "POST",
810
773
  headers: {
811
774
  Authorization: `Bearer ${apiKey}`,
812
775
  "Content-Type": "application/json"
813
776
  },
814
- body: JSON.stringify({
815
- config_key: configKey,
816
- session_id: sessionId,
817
- data
818
- }),
777
+ body: JSON.stringify(trace),
819
778
  signal: controller.signal
820
779
  });
821
780
  clearTimeout(timeoutId);
822
- } catch {
781
+ if (!response.ok) {
782
+ const text = await response.text();
783
+ log("\u274C Trace send failed:", response.status, text);
784
+ } else {
785
+ log("\u2705 Trace sent:", trace.name, trace.model);
786
+ }
787
+ } catch (err) {
788
+ log("\u274C Trace send error:", err instanceof Error ? err.message : err);
823
789
  }
824
790
  }
825
- async function shutdown() {
826
- if (sdk) {
827
- await sdk.shutdown();
828
- initialized = false;
829
- }
791
+
792
+ // src/trace/utils.ts
793
+ function generateHexId(length) {
794
+ const bytes = new Uint8Array(length / 2);
795
+ crypto.getRandomValues(bytes);
796
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
830
797
  }
831
798
  function messagesToOtelAttributes(messages, completion, model, responseId) {
832
799
  const attrs = {};
@@ -854,65 +821,28 @@ function messagesToOtelAttributes(messages, completion, model, responseId) {
854
821
  }
855
822
  return attrs;
856
823
  }
857
- function generateHexId(length) {
858
- const bytes = new Uint8Array(length / 2);
859
- crypto.getRandomValues(bytes);
860
- return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
861
- }
862
- var traceContextStorage = new AsyncLocalStorage();
863
- var fallbackTraceContext = null;
864
- async function sendTrace(trace) {
865
- const url = `${baseUrl}/v1/traces`;
866
- log("\u{1F4E4} Sending trace to:", url);
867
- log(" Session:", trace.session_id, "Config:", trace.config_key);
868
- try {
869
- const controller = new AbortController();
870
- const timeoutId = setTimeout(() => controller.abort(), 5e3);
871
- const response = await fetch(url, {
872
- method: "POST",
873
- headers: {
874
- Authorization: `Bearer ${apiKey}`,
875
- "Content-Type": "application/json"
876
- },
877
- body: JSON.stringify(trace),
878
- signal: controller.signal
879
- });
880
- clearTimeout(timeoutId);
881
- if (!response.ok) {
882
- const text = await response.text();
883
- log("\u274C Trace send failed:", response.status, text);
884
- } else {
885
- log("\u2705 Trace sent:", trace.name, trace.model);
886
- }
887
- } catch (err) {
888
- log("\u274C Trace send error:", err instanceof Error ? err.message : err);
889
- }
890
- }
891
- function wrapOpenAI(client) {
824
+
825
+ // src/trace/wrappers/openai.ts
826
+ function wrapOpenAI(client, sessionCtx) {
892
827
  const originalCreate = client.chat.completions.create.bind(
893
828
  client.chat.completions
894
829
  );
830
+ const ctx = sessionCtx;
895
831
  client.chat.completions.create = async function(...args) {
896
- const ctx = sessionStorage.getStore() || fallbackSession;
897
- if (!ctx || !initialized) {
832
+ if (!isInitialized()) {
898
833
  return originalCreate(...args);
899
834
  }
900
- let promptCtx = null;
901
- try {
902
- const { getPromptContext } = await import("./prompts-VAN5E3L4.mjs");
903
- promptCtx = getPromptContext();
904
- } catch {
905
- }
906
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
835
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
907
836
  const traceId = traceCtx?.traceId || generateHexId(32);
908
837
  const spanId = generateHexId(16);
909
838
  const parentSpanId = traceCtx?.parentSpanId;
910
839
  const params = args[0] || {};
911
840
  const startTime = Date.now();
841
+ const captureContent2 = shouldCaptureContent();
912
842
  try {
913
843
  const response = await originalCreate(...args);
914
844
  const endTime = Date.now();
915
- const attributes = captureContent ? messagesToOtelAttributes(
845
+ const attributes = captureContent2 ? messagesToOtelAttributes(
916
846
  params?.messages,
917
847
  response?.choices?.[0]?.message,
918
848
  response?.model || params?.model,
@@ -941,17 +871,13 @@ function wrapOpenAI(client) {
941
871
  prompt_tokens: response?.usage?.prompt_tokens,
942
872
  completion_tokens: response?.usage?.completion_tokens,
943
873
  total_tokens: response?.usage?.total_tokens,
944
- attributes: Object.keys(attributes).length > 0 ? attributes : void 0,
945
- prompt_key: promptCtx?.promptKey,
946
- prompt_version: promptCtx?.promptVersion,
947
- prompt_ab_test_key: promptCtx?.abTestKey,
948
- prompt_variant_index: promptCtx?.variantIndex
874
+ attributes: Object.keys(attributes).length > 0 ? attributes : void 0
949
875
  }).catch(() => {
950
876
  });
951
877
  return response;
952
878
  } catch (error) {
953
879
  const endTime = Date.now();
954
- const attributes = captureContent ? messagesToOtelAttributes(
880
+ const attributes = captureContent2 ? messagesToOtelAttributes(
955
881
  params?.messages,
956
882
  void 0,
957
883
  params?.model,
@@ -975,11 +901,7 @@ function wrapOpenAI(client) {
975
901
  duration_ms: endTime - startTime,
976
902
  status: "ERROR",
977
903
  error_message: error?.message,
978
- attributes,
979
- prompt_key: promptCtx?.promptKey,
980
- prompt_version: promptCtx?.promptVersion,
981
- prompt_ab_test_key: promptCtx?.abTestKey,
982
- prompt_variant_index: promptCtx?.variantIndex
904
+ attributes
983
905
  }).catch(() => {
984
906
  });
985
907
  throw error;
@@ -987,29 +909,26 @@ function wrapOpenAI(client) {
987
909
  };
988
910
  return client;
989
911
  }
990
- function wrapAnthropic(client) {
912
+
913
+ // src/trace/wrappers/anthropic.ts
914
+ function wrapAnthropic(client, sessionCtx) {
991
915
  const originalCreate = client.messages.create.bind(client.messages);
916
+ const ctx = sessionCtx;
992
917
  client.messages.create = async function(...args) {
993
- const ctx = sessionStorage.getStore() || fallbackSession;
994
- if (!ctx || !initialized) {
918
+ if (!isInitialized()) {
995
919
  return originalCreate(...args);
996
920
  }
997
- let promptCtx = null;
998
- try {
999
- const { getPromptContext } = await import("./prompts-VAN5E3L4.mjs");
1000
- promptCtx = getPromptContext();
1001
- } catch {
1002
- }
1003
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
921
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1004
922
  const traceId = traceCtx?.traceId || generateHexId(32);
1005
923
  const spanId = generateHexId(16);
1006
924
  const parentSpanId = traceCtx?.parentSpanId;
1007
925
  const params = args[0] || {};
1008
926
  const startTime = Date.now();
927
+ const captureContent2 = shouldCaptureContent();
1009
928
  try {
1010
929
  const response = await originalCreate(...args);
1011
930
  const endTime = Date.now();
1012
- const attributes = captureContent ? messagesToOtelAttributes(
931
+ const attributes = captureContent2 ? messagesToOtelAttributes(
1013
932
  params?.messages,
1014
933
  { role: "assistant", content: response?.content?.[0]?.text || "" },
1015
934
  response?.model || params?.model,
@@ -1041,17 +960,13 @@ function wrapAnthropic(client) {
1041
960
  prompt_tokens: response?.usage?.input_tokens,
1042
961
  completion_tokens: response?.usage?.output_tokens,
1043
962
  total_tokens: (response?.usage?.input_tokens || 0) + (response?.usage?.output_tokens || 0),
1044
- attributes: Object.keys(attributes).length > 0 ? attributes : void 0,
1045
- prompt_key: promptCtx?.promptKey,
1046
- prompt_version: promptCtx?.promptVersion,
1047
- prompt_ab_test_key: promptCtx?.abTestKey,
1048
- prompt_variant_index: promptCtx?.variantIndex
963
+ attributes: Object.keys(attributes).length > 0 ? attributes : void 0
1049
964
  }).catch(() => {
1050
965
  });
1051
966
  return response;
1052
967
  } catch (error) {
1053
968
  const endTime = Date.now();
1054
- const attributes = captureContent ? messagesToOtelAttributes(
969
+ const attributes = captureContent2 ? messagesToOtelAttributes(
1055
970
  params?.messages,
1056
971
  void 0,
1057
972
  params?.model,
@@ -1078,11 +993,7 @@ function wrapAnthropic(client) {
1078
993
  duration_ms: endTime - startTime,
1079
994
  status: "ERROR",
1080
995
  error_message: error?.message,
1081
- attributes,
1082
- prompt_key: promptCtx?.promptKey,
1083
- prompt_version: promptCtx?.promptVersion,
1084
- prompt_ab_test_key: promptCtx?.abTestKey,
1085
- prompt_variant_index: promptCtx?.variantIndex
996
+ attributes
1086
997
  }).catch(() => {
1087
998
  });
1088
999
  throw error;
@@ -1090,24 +1001,21 @@ function wrapAnthropic(client) {
1090
1001
  };
1091
1002
  return client;
1092
1003
  }
1093
- function wrapGoogleAI(model) {
1004
+
1005
+ // src/trace/wrappers/google-ai.ts
1006
+ function wrapGoogleAI(model, sessionCtx) {
1094
1007
  const originalGenerate = model.generateContent.bind(model);
1008
+ const ctx = sessionCtx;
1095
1009
  model.generateContent = async function(...args) {
1096
- const ctx = sessionStorage.getStore() || fallbackSession;
1097
- if (!ctx || !initialized) {
1010
+ if (!isInitialized()) {
1098
1011
  return originalGenerate(...args);
1099
1012
  }
1100
- let promptCtx = null;
1101
- try {
1102
- const { getPromptContext } = await import("./prompts-VAN5E3L4.mjs");
1103
- promptCtx = getPromptContext();
1104
- } catch {
1105
- }
1106
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1013
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1107
1014
  const traceId = traceCtx?.traceId || generateHexId(32);
1108
1015
  const spanId = generateHexId(16);
1109
1016
  const parentSpanId = traceCtx?.parentSpanId;
1110
1017
  const startTime = Date.now();
1018
+ const captureContent2 = shouldCaptureContent();
1111
1019
  try {
1112
1020
  const response = await originalGenerate(...args);
1113
1021
  const endTime = Date.now();
@@ -1115,7 +1023,7 @@ function wrapGoogleAI(model) {
1115
1023
  const usage = result?.usageMetadata;
1116
1024
  const modelName = model?.model || "gemini";
1117
1025
  const attributes = {};
1118
- if (captureContent) {
1026
+ if (captureContent2) {
1119
1027
  attributes["gen_ai.request.model"] = modelName;
1120
1028
  attributes["gen_ai.response.model"] = modelName;
1121
1029
  const input = args[0];
@@ -1158,11 +1066,7 @@ function wrapGoogleAI(model) {
1158
1066
  prompt_tokens: usage?.promptTokenCount,
1159
1067
  completion_tokens: usage?.candidatesTokenCount,
1160
1068
  total_tokens: usage?.totalTokenCount,
1161
- attributes: Object.keys(attributes).length > 0 ? attributes : void 0,
1162
- prompt_key: promptCtx?.promptKey,
1163
- prompt_version: promptCtx?.promptVersion,
1164
- prompt_ab_test_key: promptCtx?.abTestKey,
1165
- prompt_variant_index: promptCtx?.variantIndex
1069
+ attributes: Object.keys(attributes).length > 0 ? attributes : void 0
1166
1070
  }).catch(() => {
1167
1071
  });
1168
1072
  return response;
@@ -1170,7 +1074,7 @@ function wrapGoogleAI(model) {
1170
1074
  const endTime = Date.now();
1171
1075
  const modelName = model?.model || "gemini";
1172
1076
  const attributes = {};
1173
- if (captureContent) {
1077
+ if (captureContent2) {
1174
1078
  attributes["gen_ai.request.model"] = modelName;
1175
1079
  attributes["error.message"] = error?.message;
1176
1080
  const input = args[0];
@@ -1194,11 +1098,7 @@ function wrapGoogleAI(model) {
1194
1098
  duration_ms: endTime - startTime,
1195
1099
  status: "ERROR",
1196
1100
  error_message: error?.message,
1197
- attributes: captureContent ? attributes : void 0,
1198
- prompt_key: promptCtx?.promptKey,
1199
- prompt_version: promptCtx?.promptVersion,
1200
- prompt_ab_test_key: promptCtx?.abTestKey,
1201
- prompt_variant_index: promptCtx?.variantIndex
1101
+ attributes: captureContent2 ? attributes : void 0
1202
1102
  }).catch(() => {
1203
1103
  });
1204
1104
  throw error;
@@ -1206,7 +1106,8 @@ function wrapGoogleAI(model) {
1206
1106
  };
1207
1107
  return model;
1208
1108
  }
1209
- var aiSdkDebug = false;
1109
+
1110
+ // src/trace/wrappers/vercel-ai/utils.ts
1210
1111
  function extractUsageFromResult(result, directUsage) {
1211
1112
  let usage = directUsage ?? result?.usage;
1212
1113
  const isValidNumber = (v) => v !== null && v !== void 0 && !Number.isNaN(v);
@@ -1234,38 +1135,25 @@ function extractUsageFromResult(result, directUsage) {
1234
1135
  }
1235
1136
  return { promptTokens, completionTokens, totalTokens, cost };
1236
1137
  }
1237
- function wrapAISDK(ai, options) {
1238
- const aiModule = ai;
1239
- aiSdkDebug = options?.debug ?? false;
1240
- return {
1241
- generateText: createGenerateTextWrapper(aiModule),
1242
- streamText: createStreamTextWrapper(aiModule),
1243
- generateObject: aiModule.generateObject ? createGenerateObjectWrapper(aiModule) : void 0,
1244
- streamObject: aiModule.streamObject ? createStreamObjectWrapper(aiModule) : void 0
1245
- };
1246
- }
1247
- function createGenerateTextWrapper(aiModule) {
1138
+
1139
+ // src/trace/wrappers/vercel-ai/generate-text.ts
1140
+ function createGenerateTextWrapper(aiModule, sessionCtx, debug = false) {
1141
+ const ctx = sessionCtx;
1248
1142
  return async (...args) => {
1249
- const ctx = sessionStorage.getStore() || fallbackSession;
1250
- if (!ctx || !initialized) {
1143
+ if (!isInitialized()) {
1251
1144
  return aiModule.generateText(...args);
1252
1145
  }
1253
- let promptCtx = null;
1254
- try {
1255
- const { getPromptContext } = await import("./prompts-VAN5E3L4.mjs");
1256
- promptCtx = getPromptContext();
1257
- } catch {
1258
- }
1259
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1146
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1260
1147
  const traceId = traceCtx?.traceId || generateHexId(32);
1261
1148
  const spanId = generateHexId(16);
1262
1149
  const parentSpanId = traceCtx?.parentSpanId;
1263
1150
  const params = args[0] || {};
1264
1151
  const startTime = Date.now();
1152
+ const captureContent2 = shouldCaptureContent();
1265
1153
  try {
1266
1154
  const result = await aiModule.generateText(...args);
1267
1155
  const endTime = Date.now();
1268
- if (aiSdkDebug) {
1156
+ if (debug || isDebugMode()) {
1269
1157
  console.log(
1270
1158
  "\n\u{1F50D} [Fallom Debug] generateText result keys:",
1271
1159
  Object.keys(result || {})
@@ -1274,14 +1162,6 @@ function createGenerateTextWrapper(aiModule) {
1274
1162
  "\u{1F50D} [Fallom Debug] result.usage:",
1275
1163
  JSON.stringify(result?.usage, null, 2)
1276
1164
  );
1277
- console.log(
1278
- "\u{1F50D} [Fallom Debug] result.response keys:",
1279
- Object.keys(result?.response || {})
1280
- );
1281
- console.log(
1282
- "\u{1F50D} [Fallom Debug] result.response.usage:",
1283
- JSON.stringify(result?.response?.usage, null, 2)
1284
- );
1285
1165
  console.log(
1286
1166
  "\u{1F50D} [Fallom Debug] result.experimental_providerMetadata:",
1287
1167
  JSON.stringify(result?.experimental_providerMetadata, null, 2)
@@ -1289,7 +1169,7 @@ function createGenerateTextWrapper(aiModule) {
1289
1169
  }
1290
1170
  const modelId = result?.response?.modelId || params?.model?.modelId || String(params?.model || "unknown");
1291
1171
  const attributes = {};
1292
- if (captureContent) {
1172
+ if (captureContent2) {
1293
1173
  attributes["gen_ai.request.model"] = modelId;
1294
1174
  attributes["gen_ai.response.model"] = modelId;
1295
1175
  if (params?.prompt) {
@@ -1339,11 +1219,7 @@ function createGenerateTextWrapper(aiModule) {
1339
1219
  prompt_tokens: usage.promptTokens,
1340
1220
  completion_tokens: usage.completionTokens,
1341
1221
  total_tokens: usage.totalTokens,
1342
- attributes: captureContent ? attributes : void 0,
1343
- prompt_key: promptCtx?.promptKey,
1344
- prompt_version: promptCtx?.promptVersion,
1345
- prompt_ab_test_key: promptCtx?.abTestKey,
1346
- prompt_variant_index: promptCtx?.variantIndex
1222
+ attributes: captureContent2 ? attributes : void 0
1347
1223
  }).catch(() => {
1348
1224
  });
1349
1225
  return result;
@@ -1364,52 +1240,44 @@ function createGenerateTextWrapper(aiModule) {
1364
1240
  end_time: new Date(endTime).toISOString(),
1365
1241
  duration_ms: endTime - startTime,
1366
1242
  status: "ERROR",
1367
- error_message: error?.message,
1368
- prompt_key: promptCtx?.promptKey,
1369
- prompt_version: promptCtx?.promptVersion,
1370
- prompt_ab_test_key: promptCtx?.abTestKey,
1371
- prompt_variant_index: promptCtx?.variantIndex
1243
+ error_message: error?.message
1372
1244
  }).catch(() => {
1373
1245
  });
1374
1246
  throw error;
1375
1247
  }
1376
1248
  };
1377
1249
  }
1378
- function createStreamTextWrapper(aiModule) {
1250
+
1251
+ // src/trace/wrappers/vercel-ai/stream-text.ts
1252
+ function log2(...args) {
1253
+ if (isDebugMode()) console.log("[Fallom]", ...args);
1254
+ }
1255
+ function createStreamTextWrapper(aiModule, sessionCtx, debug = false) {
1256
+ const ctx = sessionCtx;
1379
1257
  return async (...args) => {
1380
- const ctx = sessionStorage.getStore() || fallbackSession;
1381
1258
  const params = args[0] || {};
1382
1259
  const startTime = Date.now();
1260
+ const captureContent2 = shouldCaptureContent();
1383
1261
  const result = await aiModule.streamText(...args);
1384
- if (!ctx || !initialized) {
1262
+ if (!isInitialized()) {
1385
1263
  return result;
1386
1264
  }
1387
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1265
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1388
1266
  const traceId = traceCtx?.traceId || generateHexId(32);
1389
1267
  const spanId = generateHexId(16);
1390
1268
  const parentSpanId = traceCtx?.parentSpanId;
1391
1269
  let firstTokenTime = null;
1392
1270
  const modelId = params?.model?.modelId || String(params?.model || "unknown");
1393
- let promptCtx = null;
1394
- try {
1395
- const { getPromptContext } = await import("./prompts-VAN5E3L4.mjs");
1396
- promptCtx = getPromptContext();
1397
- } catch {
1398
- }
1399
1271
  if (result?.usage) {
1400
1272
  result.usage.then(async (rawUsage) => {
1401
1273
  const endTime = Date.now();
1402
- if (aiSdkDebug) {
1274
+ if (debug || isDebugMode()) {
1403
1275
  console.log(
1404
1276
  "\n\u{1F50D} [Fallom Debug] streamText usage:",
1405
1277
  JSON.stringify(rawUsage, null, 2)
1406
1278
  );
1407
- console.log(
1408
- "\u{1F50D} [Fallom Debug] streamText result keys:",
1409
- Object.keys(result || {})
1410
- );
1411
1279
  }
1412
- log("\u{1F4CA} streamText usage:", JSON.stringify(rawUsage, null, 2));
1280
+ log2("\u{1F4CA} streamText usage:", JSON.stringify(rawUsage, null, 2));
1413
1281
  let providerMetadata = result?.experimental_providerMetadata;
1414
1282
  if (providerMetadata && typeof providerMetadata.then === "function") {
1415
1283
  try {
@@ -1423,7 +1291,7 @@ function createStreamTextWrapper(aiModule) {
1423
1291
  rawUsage
1424
1292
  );
1425
1293
  const attributes = {};
1426
- if (captureContent) {
1294
+ if (captureContent2) {
1427
1295
  attributes["gen_ai.request.model"] = modelId;
1428
1296
  if (params?.prompt) {
1429
1297
  attributes["gen_ai.prompt.0.role"] = "user";
@@ -1457,17 +1325,13 @@ function createStreamTextWrapper(aiModule) {
1457
1325
  completion_tokens: usage.completionTokens,
1458
1326
  total_tokens: usage.totalTokens,
1459
1327
  time_to_first_token_ms: firstTokenTime ? firstTokenTime - startTime : void 0,
1460
- attributes: captureContent ? attributes : void 0,
1461
- prompt_key: promptCtx?.promptKey,
1462
- prompt_version: promptCtx?.promptVersion,
1463
- prompt_ab_test_key: promptCtx?.abTestKey,
1464
- prompt_variant_index: promptCtx?.variantIndex
1328
+ attributes: captureContent2 ? attributes : void 0
1465
1329
  };
1466
1330
  sendTrace(tracePayload).catch(() => {
1467
1331
  });
1468
1332
  }).catch((error) => {
1469
1333
  const endTime = Date.now();
1470
- log("\u274C streamText error:", error?.message);
1334
+ log2("\u274C streamText error:", error?.message);
1471
1335
  sendTrace({
1472
1336
  config_key: ctx.configKey,
1473
1337
  session_id: ctx.sessionId,
@@ -1482,11 +1346,7 @@ function createStreamTextWrapper(aiModule) {
1482
1346
  end_time: new Date(endTime).toISOString(),
1483
1347
  duration_ms: endTime - startTime,
1484
1348
  status: "ERROR",
1485
- error_message: error?.message,
1486
- prompt_key: promptCtx?.promptKey,
1487
- prompt_version: promptCtx?.promptVersion,
1488
- prompt_ab_test_key: promptCtx?.abTestKey,
1489
- prompt_variant_index: promptCtx?.variantIndex
1349
+ error_message: error?.message
1490
1350
  }).catch(() => {
1491
1351
  });
1492
1352
  });
@@ -1497,7 +1357,7 @@ function createStreamTextWrapper(aiModule) {
1497
1357
  for await (const chunk of originalTextStream) {
1498
1358
  if (!firstTokenTime) {
1499
1359
  firstTokenTime = Date.now();
1500
- log("\u23F1\uFE0F Time to first token:", firstTokenTime - startTime, "ms");
1360
+ log2("\u23F1\uFE0F Time to first token:", firstTokenTime - startTime, "ms");
1501
1361
  }
1502
1362
  yield chunk;
1503
1363
  }
@@ -1514,28 +1374,25 @@ function createStreamTextWrapper(aiModule) {
1514
1374
  return result;
1515
1375
  };
1516
1376
  }
1517
- function createGenerateObjectWrapper(aiModule) {
1377
+
1378
+ // src/trace/wrappers/vercel-ai/generate-object.ts
1379
+ function createGenerateObjectWrapper(aiModule, sessionCtx, debug = false) {
1380
+ const ctx = sessionCtx;
1518
1381
  return async (...args) => {
1519
- const ctx = sessionStorage.getStore() || fallbackSession;
1520
- if (!ctx || !initialized) {
1382
+ if (!isInitialized()) {
1521
1383
  return aiModule.generateObject(...args);
1522
1384
  }
1523
- let promptCtx = null;
1524
- try {
1525
- const { getPromptContext } = await import("./prompts-VAN5E3L4.mjs");
1526
- promptCtx = getPromptContext();
1527
- } catch {
1528
- }
1529
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1385
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1530
1386
  const traceId = traceCtx?.traceId || generateHexId(32);
1531
1387
  const spanId = generateHexId(16);
1532
1388
  const parentSpanId = traceCtx?.parentSpanId;
1533
1389
  const params = args[0] || {};
1534
1390
  const startTime = Date.now();
1391
+ const captureContent2 = shouldCaptureContent();
1535
1392
  try {
1536
1393
  const result = await aiModule.generateObject(...args);
1537
1394
  const endTime = Date.now();
1538
- if (aiSdkDebug) {
1395
+ if (debug || isDebugMode()) {
1539
1396
  console.log(
1540
1397
  "\n\u{1F50D} [Fallom Debug] generateObject result keys:",
1541
1398
  Object.keys(result || {})
@@ -1544,18 +1401,10 @@ function createGenerateObjectWrapper(aiModule) {
1544
1401
  "\u{1F50D} [Fallom Debug] result.usage:",
1545
1402
  JSON.stringify(result?.usage, null, 2)
1546
1403
  );
1547
- console.log(
1548
- "\u{1F50D} [Fallom Debug] result.response keys:",
1549
- Object.keys(result?.response || {})
1550
- );
1551
- console.log(
1552
- "\u{1F50D} [Fallom Debug] result.response.usage:",
1553
- JSON.stringify(result?.response?.usage, null, 2)
1554
- );
1555
1404
  }
1556
1405
  const modelId = result?.response?.modelId || params?.model?.modelId || String(params?.model || "unknown");
1557
1406
  const attributes = {};
1558
- if (captureContent) {
1407
+ if (captureContent2) {
1559
1408
  attributes["gen_ai.request.model"] = modelId;
1560
1409
  attributes["gen_ai.response.model"] = modelId;
1561
1410
  if (result?.object) {
@@ -1594,11 +1443,7 @@ function createGenerateObjectWrapper(aiModule) {
1594
1443
  prompt_tokens: usage.promptTokens,
1595
1444
  completion_tokens: usage.completionTokens,
1596
1445
  total_tokens: usage.totalTokens,
1597
- attributes: captureContent ? attributes : void 0,
1598
- prompt_key: promptCtx?.promptKey,
1599
- prompt_version: promptCtx?.promptVersion,
1600
- prompt_ab_test_key: promptCtx?.abTestKey,
1601
- prompt_variant_index: promptCtx?.variantIndex
1446
+ attributes: captureContent2 ? attributes : void 0
1602
1447
  }).catch(() => {
1603
1448
  });
1604
1449
  return result;
@@ -1619,53 +1464,45 @@ function createGenerateObjectWrapper(aiModule) {
1619
1464
  end_time: new Date(endTime).toISOString(),
1620
1465
  duration_ms: endTime - startTime,
1621
1466
  status: "ERROR",
1622
- error_message: error?.message,
1623
- prompt_key: promptCtx?.promptKey,
1624
- prompt_version: promptCtx?.promptVersion,
1625
- prompt_ab_test_key: promptCtx?.abTestKey,
1626
- prompt_variant_index: promptCtx?.variantIndex
1467
+ error_message: error?.message
1627
1468
  }).catch(() => {
1628
1469
  });
1629
1470
  throw error;
1630
1471
  }
1631
1472
  };
1632
1473
  }
1633
- function createStreamObjectWrapper(aiModule) {
1474
+
1475
+ // src/trace/wrappers/vercel-ai/stream-object.ts
1476
+ function log3(...args) {
1477
+ if (isDebugMode()) console.log("[Fallom]", ...args);
1478
+ }
1479
+ function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
1480
+ const ctx = sessionCtx;
1634
1481
  return async (...args) => {
1635
- const ctx = sessionStorage.getStore() || fallbackSession;
1636
1482
  const params = args[0] || {};
1637
1483
  const startTime = Date.now();
1484
+ const captureContent2 = shouldCaptureContent();
1638
1485
  const result = await aiModule.streamObject(...args);
1639
- log("\u{1F50D} streamObject result keys:", Object.keys(result || {}));
1640
- if (!ctx || !initialized) {
1486
+ log3("\u{1F50D} streamObject result keys:", Object.keys(result || {}));
1487
+ if (!isInitialized()) {
1641
1488
  return result;
1642
1489
  }
1643
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1490
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1644
1491
  const traceId = traceCtx?.traceId || generateHexId(32);
1645
1492
  const spanId = generateHexId(16);
1646
1493
  const parentSpanId = traceCtx?.parentSpanId;
1647
1494
  let firstTokenTime = null;
1648
1495
  const modelId = params?.model?.modelId || String(params?.model || "unknown");
1649
- let promptCtx = null;
1650
- try {
1651
- const { getPromptContext } = await import("./prompts-VAN5E3L4.mjs");
1652
- promptCtx = getPromptContext();
1653
- } catch {
1654
- }
1655
1496
  if (result?.usage) {
1656
1497
  result.usage.then(async (rawUsage) => {
1657
1498
  const endTime = Date.now();
1658
- if (aiSdkDebug) {
1499
+ if (debug || isDebugMode()) {
1659
1500
  console.log(
1660
1501
  "\n\u{1F50D} [Fallom Debug] streamObject usage:",
1661
1502
  JSON.stringify(rawUsage, null, 2)
1662
1503
  );
1663
- console.log(
1664
- "\u{1F50D} [Fallom Debug] streamObject result keys:",
1665
- Object.keys(result || {})
1666
- );
1667
1504
  }
1668
- log("\u{1F4CA} streamObject usage:", JSON.stringify(rawUsage, null, 2));
1505
+ log3("\u{1F4CA} streamObject usage:", JSON.stringify(rawUsage, null, 2));
1669
1506
  let providerMetadata = result?.experimental_providerMetadata;
1670
1507
  if (providerMetadata && typeof providerMetadata.then === "function") {
1671
1508
  try {
@@ -1679,7 +1516,7 @@ function createStreamObjectWrapper(aiModule) {
1679
1516
  rawUsage
1680
1517
  );
1681
1518
  const attributes = {};
1682
- if (captureContent) {
1519
+ if (captureContent2) {
1683
1520
  attributes["gen_ai.request.model"] = modelId;
1684
1521
  }
1685
1522
  if (firstTokenTime) {
@@ -1708,11 +1545,7 @@ function createStreamObjectWrapper(aiModule) {
1708
1545
  prompt_tokens: usage.promptTokens,
1709
1546
  completion_tokens: usage.completionTokens,
1710
1547
  total_tokens: usage.totalTokens,
1711
- attributes: captureContent ? attributes : void 0,
1712
- prompt_key: promptCtx?.promptKey,
1713
- prompt_version: promptCtx?.promptVersion,
1714
- prompt_ab_test_key: promptCtx?.abTestKey,
1715
- prompt_variant_index: promptCtx?.variantIndex
1548
+ attributes: captureContent2 ? attributes : void 0
1716
1549
  }).catch(() => {
1717
1550
  });
1718
1551
  }).catch((error) => {
@@ -1731,11 +1564,7 @@ function createStreamObjectWrapper(aiModule) {
1731
1564
  end_time: new Date(endTime).toISOString(),
1732
1565
  duration_ms: endTime - startTime,
1733
1566
  status: "ERROR",
1734
- error_message: error?.message,
1735
- prompt_key: promptCtx?.promptKey,
1736
- prompt_version: promptCtx?.promptVersion,
1737
- prompt_ab_test_key: promptCtx?.abTestKey,
1738
- prompt_variant_index: promptCtx?.variantIndex
1567
+ error_message: error?.message
1739
1568
  }).catch(() => {
1740
1569
  });
1741
1570
  });
@@ -1746,7 +1575,7 @@ function createStreamObjectWrapper(aiModule) {
1746
1575
  for await (const chunk of originalStream) {
1747
1576
  if (!firstTokenTime) {
1748
1577
  firstTokenTime = Date.now();
1749
- log("\u23F1\uFE0F Time to first token:", firstTokenTime - startTime, "ms");
1578
+ log3("\u23F1\uFE0F Time to first token:", firstTokenTime - startTime, "ms");
1750
1579
  }
1751
1580
  yield chunk;
1752
1581
  }
@@ -1763,20 +1592,27 @@ function createStreamObjectWrapper(aiModule) {
1763
1592
  return result;
1764
1593
  };
1765
1594
  }
1766
- function wrapMastraAgent(agent) {
1595
+
1596
+ // src/trace/wrappers/vercel-ai/index.ts
1597
+ function wrapAISDK(ai, sessionCtx, options) {
1598
+ const debug = options?.debug ?? false;
1599
+ return {
1600
+ generateText: createGenerateTextWrapper(ai, sessionCtx, debug),
1601
+ streamText: createStreamTextWrapper(ai, sessionCtx, debug),
1602
+ generateObject: ai.generateObject ? createGenerateObjectWrapper(ai, sessionCtx, debug) : void 0,
1603
+ streamObject: ai.streamObject ? createStreamObjectWrapper(ai, sessionCtx, debug) : void 0
1604
+ };
1605
+ }
1606
+
1607
+ // src/trace/wrappers/mastra.ts
1608
+ function wrapMastraAgent(agent, sessionCtx) {
1767
1609
  const originalGenerate = agent.generate.bind(agent);
1768
1610
  const agentName = agent.name || "MastraAgent";
1611
+ const ctx = sessionCtx;
1769
1612
  agent.generate = async function(...args) {
1770
- const ctx = sessionStorage.getStore() || fallbackSession;
1771
- if (!ctx || !initialized) {
1613
+ if (!isInitialized()) {
1772
1614
  return originalGenerate(...args);
1773
1615
  }
1774
- let promptCtx = null;
1775
- try {
1776
- const { getPromptContext } = await import("./prompts-VAN5E3L4.mjs");
1777
- promptCtx = getPromptContext();
1778
- } catch {
1779
- }
1780
1616
  const traceId = generateHexId(32);
1781
1617
  const spanId = generateHexId(16);
1782
1618
  const startTime = Date.now();
@@ -1848,11 +1684,7 @@ function wrapMastraAgent(agent) {
1848
1684
  prompt_tokens: result?.usage?.promptTokens,
1849
1685
  completion_tokens: result?.usage?.completionTokens,
1850
1686
  total_tokens: result?.usage?.totalTokens,
1851
- attributes,
1852
- prompt_key: promptCtx?.promptKey,
1853
- prompt_version: promptCtx?.promptVersion,
1854
- prompt_ab_test_key: promptCtx?.abTestKey,
1855
- prompt_variant_index: promptCtx?.variantIndex
1687
+ attributes
1856
1688
  };
1857
1689
  sendTrace(traceData).catch(() => {
1858
1690
  });
@@ -1871,11 +1703,7 @@ function wrapMastraAgent(agent) {
1871
1703
  end_time: new Date(endTime).toISOString(),
1872
1704
  duration_ms: endTime - startTime,
1873
1705
  status: "ERROR",
1874
- error_message: error instanceof Error ? error.message : String(error),
1875
- prompt_key: promptCtx?.promptKey,
1876
- prompt_version: promptCtx?.promptVersion,
1877
- prompt_ab_test_key: promptCtx?.abTestKey,
1878
- prompt_variant_index: promptCtx?.variantIndex
1706
+ error_message: error instanceof Error ? error.message : String(error)
1879
1707
  };
1880
1708
  sendTrace(traceData).catch(() => {
1881
1709
  });
@@ -1885,38 +1713,213 @@ function wrapMastraAgent(agent) {
1885
1713
  return agent;
1886
1714
  }
1887
1715
 
1888
- // src/models.ts
1889
- var models_exports = {};
1890
- __export(models_exports, {
1716
+ // src/trace/session.ts
1717
+ var FallomSession = class {
1718
+ constructor(options) {
1719
+ this.ctx = {
1720
+ configKey: options.configKey,
1721
+ sessionId: options.sessionId,
1722
+ customerId: options.customerId
1723
+ };
1724
+ }
1725
+ /** Get the session context. */
1726
+ getContext() {
1727
+ return { ...this.ctx };
1728
+ }
1729
+ /**
1730
+ * Get model assignment for this session (A/B testing).
1731
+ */
1732
+ async getModel(configKeyOrOptions, options) {
1733
+ let configKey;
1734
+ let opts;
1735
+ if (typeof configKeyOrOptions === "string") {
1736
+ configKey = configKeyOrOptions;
1737
+ opts = options || {};
1738
+ } else {
1739
+ configKey = this.ctx.configKey;
1740
+ opts = configKeyOrOptions || {};
1741
+ }
1742
+ const { get: get2 } = await import("./models-JKMOBZUO.mjs");
1743
+ return get2(configKey, this.ctx.sessionId, opts);
1744
+ }
1745
+ /**
1746
+ * Wrap a Vercel AI SDK model to trace all calls.
1747
+ */
1748
+ traceModel(model) {
1749
+ const ctx = this.ctx;
1750
+ const tracedModel = Object.create(model);
1751
+ if (model.doGenerate) {
1752
+ const originalDoGenerate = model.doGenerate.bind(model);
1753
+ tracedModel.doGenerate = async function(...args) {
1754
+ if (!isInitialized()) return originalDoGenerate(...args);
1755
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1756
+ const traceId = traceCtx?.traceId || generateHexId(32);
1757
+ const spanId = generateHexId(16);
1758
+ const startTime = Date.now();
1759
+ try {
1760
+ const result = await originalDoGenerate(...args);
1761
+ const endTime = Date.now();
1762
+ const modelId = model.modelId || "unknown";
1763
+ const usage = result?.usage || result?.rawResponse?.usage;
1764
+ sendTrace({
1765
+ config_key: ctx.configKey,
1766
+ session_id: ctx.sessionId,
1767
+ customer_id: ctx.customerId,
1768
+ trace_id: traceId,
1769
+ span_id: spanId,
1770
+ parent_span_id: traceCtx?.parentSpanId,
1771
+ name: "generateText",
1772
+ kind: "llm",
1773
+ model: modelId,
1774
+ start_time: new Date(startTime).toISOString(),
1775
+ end_time: new Date(endTime).toISOString(),
1776
+ duration_ms: endTime - startTime,
1777
+ status: "OK",
1778
+ prompt_tokens: usage?.promptTokens,
1779
+ completion_tokens: usage?.completionTokens,
1780
+ total_tokens: usage?.totalTokens,
1781
+ attributes: shouldCaptureContent() && usage ? { "fallom.raw.usage": JSON.stringify(usage) } : void 0
1782
+ }).catch(() => {
1783
+ });
1784
+ return result;
1785
+ } catch (error) {
1786
+ const endTime = Date.now();
1787
+ sendTrace({
1788
+ config_key: ctx.configKey,
1789
+ session_id: ctx.sessionId,
1790
+ customer_id: ctx.customerId,
1791
+ trace_id: traceId,
1792
+ span_id: spanId,
1793
+ parent_span_id: traceCtx?.parentSpanId,
1794
+ name: "generateText",
1795
+ kind: "llm",
1796
+ model: model.modelId || "unknown",
1797
+ start_time: new Date(startTime).toISOString(),
1798
+ end_time: new Date(endTime).toISOString(),
1799
+ duration_ms: endTime - startTime,
1800
+ status: "ERROR",
1801
+ error_message: error instanceof Error ? error.message : String(error)
1802
+ }).catch(() => {
1803
+ });
1804
+ throw error;
1805
+ }
1806
+ };
1807
+ }
1808
+ if (model.doStream) {
1809
+ const originalDoStream = model.doStream.bind(model);
1810
+ tracedModel.doStream = async function(...args) {
1811
+ if (!isInitialized()) return originalDoStream(...args);
1812
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1813
+ const traceId = traceCtx?.traceId || generateHexId(32);
1814
+ const spanId = generateHexId(16);
1815
+ const startTime = Date.now();
1816
+ const modelId = model.modelId || "unknown";
1817
+ try {
1818
+ const result = await originalDoStream(...args);
1819
+ sendTrace({
1820
+ config_key: ctx.configKey,
1821
+ session_id: ctx.sessionId,
1822
+ customer_id: ctx.customerId,
1823
+ trace_id: traceId,
1824
+ span_id: spanId,
1825
+ parent_span_id: traceCtx?.parentSpanId,
1826
+ name: "streamText",
1827
+ kind: "llm",
1828
+ model: modelId,
1829
+ start_time: new Date(startTime).toISOString(),
1830
+ end_time: new Date(Date.now()).toISOString(),
1831
+ duration_ms: Date.now() - startTime,
1832
+ status: "OK",
1833
+ is_streaming: true
1834
+ }).catch(() => {
1835
+ });
1836
+ return result;
1837
+ } catch (error) {
1838
+ sendTrace({
1839
+ config_key: ctx.configKey,
1840
+ session_id: ctx.sessionId,
1841
+ customer_id: ctx.customerId,
1842
+ trace_id: traceId,
1843
+ span_id: spanId,
1844
+ parent_span_id: traceCtx?.parentSpanId,
1845
+ name: "streamText",
1846
+ kind: "llm",
1847
+ model: modelId,
1848
+ start_time: new Date(startTime).toISOString(),
1849
+ end_time: new Date(Date.now()).toISOString(),
1850
+ duration_ms: Date.now() - startTime,
1851
+ status: "ERROR",
1852
+ error_message: error instanceof Error ? error.message : String(error),
1853
+ is_streaming: true
1854
+ }).catch(() => {
1855
+ });
1856
+ throw error;
1857
+ }
1858
+ };
1859
+ }
1860
+ return tracedModel;
1861
+ }
1862
+ /** Wrap OpenAI client. Delegates to shared wrapper. */
1863
+ wrapOpenAI(client) {
1864
+ return wrapOpenAI(client, this.ctx);
1865
+ }
1866
+ /** Wrap Anthropic client. Delegates to shared wrapper. */
1867
+ wrapAnthropic(client) {
1868
+ return wrapAnthropic(client, this.ctx);
1869
+ }
1870
+ /** Wrap Google AI model. Delegates to shared wrapper. */
1871
+ wrapGoogleAI(model) {
1872
+ return wrapGoogleAI(model, this.ctx);
1873
+ }
1874
+ /** Wrap Vercel AI SDK. Delegates to shared wrapper. */
1875
+ wrapAISDK(ai, options) {
1876
+ return wrapAISDK(ai, this.ctx, options);
1877
+ }
1878
+ /** Wrap Mastra agent. Delegates to shared wrapper. */
1879
+ wrapMastraAgent(agent) {
1880
+ return wrapMastraAgent(agent, this.ctx);
1881
+ }
1882
+ };
1883
+ function session(options) {
1884
+ return new FallomSession(options);
1885
+ }
1886
+
1887
+ // src/prompts.ts
1888
+ var prompts_exports = {};
1889
+ __export(prompts_exports, {
1890
+ clearPromptContext: () => clearPromptContext,
1891
1891
  get: () => get,
1892
+ getAB: () => getAB,
1893
+ getPromptContext: () => getPromptContext,
1892
1894
  init: () => init3
1893
1895
  });
1894
1896
  import { createHash } from "crypto";
1895
1897
  var apiKey2 = null;
1896
- var baseUrl2 = "https://configs.fallom.com";
1898
+ var baseUrl2 = "https://prompts.fallom.com";
1897
1899
  var initialized2 = false;
1898
1900
  var syncInterval = null;
1899
1901
  var debugMode2 = false;
1900
- var configCache = /* @__PURE__ */ new Map();
1902
+ var promptCache = /* @__PURE__ */ new Map();
1903
+ var promptABCache = /* @__PURE__ */ new Map();
1904
+ var promptContext = null;
1901
1905
  var SYNC_TIMEOUT = 2e3;
1902
- var RECORD_TIMEOUT = 1e3;
1903
- function log2(msg) {
1906
+ function log4(msg) {
1904
1907
  if (debugMode2) {
1905
- console.log(`[Fallom] ${msg}`);
1908
+ console.log(`[Fallom Prompts] ${msg}`);
1906
1909
  }
1907
1910
  }
1908
1911
  function init3(options = {}) {
1909
1912
  apiKey2 = options.apiKey || process.env.FALLOM_API_KEY || null;
1910
- baseUrl2 = options.baseUrl || process.env.FALLOM_CONFIGS_URL || process.env.FALLOM_BASE_URL || "https://configs.fallom.com";
1913
+ baseUrl2 = options.baseUrl || process.env.FALLOM_PROMPTS_URL || process.env.FALLOM_BASE_URL || "https://prompts.fallom.com";
1911
1914
  initialized2 = true;
1912
1915
  if (!apiKey2) {
1913
1916
  return;
1914
1917
  }
1915
- fetchConfigs().catch(() => {
1918
+ fetchAll().catch(() => {
1916
1919
  });
1917
1920
  if (!syncInterval) {
1918
1921
  syncInterval = setInterval(() => {
1919
- fetchConfigs().catch(() => {
1922
+ fetchAll().catch(() => {
1920
1923
  });
1921
1924
  }, 3e4);
1922
1925
  syncInterval.unref();
@@ -1930,202 +1933,195 @@ function ensureInit() {
1930
1933
  }
1931
1934
  }
1932
1935
  }
1933
- async function fetchConfigs(timeout = SYNC_TIMEOUT) {
1934
- if (!apiKey2) {
1935
- log2("_fetchConfigs: No API key, skipping");
1936
- return;
1937
- }
1936
+ async function fetchAll() {
1937
+ await Promise.all([fetchPrompts(), fetchPromptABTests()]);
1938
+ }
1939
+ async function fetchPrompts(timeout = SYNC_TIMEOUT) {
1940
+ if (!apiKey2) return;
1938
1941
  try {
1939
- log2(`Fetching configs from ${baseUrl2}/configs`);
1940
1942
  const controller = new AbortController();
1941
1943
  const timeoutId = setTimeout(() => controller.abort(), timeout);
1942
- const resp = await fetch(`${baseUrl2}/configs`, {
1944
+ const resp = await fetch(`${baseUrl2}/prompts`, {
1943
1945
  headers: { Authorization: `Bearer ${apiKey2}` },
1944
1946
  signal: controller.signal
1945
1947
  });
1946
1948
  clearTimeout(timeoutId);
1947
- log2(`Response status: ${resp.status}`);
1948
1949
  if (resp.ok) {
1949
1950
  const data = await resp.json();
1950
- const configs = data.configs || [];
1951
- log2(`Got ${configs.length} configs: ${configs.map((c) => c.key)}`);
1952
- for (const c of configs) {
1953
- const key = c.key;
1954
- const version = c.version || 1;
1955
- log2(`Config '${key}' v${version}: ${JSON.stringify(c.variants)}`);
1956
- if (!configCache.has(key)) {
1957
- configCache.set(key, { versions: /* @__PURE__ */ new Map(), latest: null });
1951
+ for (const p of data.prompts || []) {
1952
+ if (!promptCache.has(p.key)) {
1953
+ promptCache.set(p.key, { versions: /* @__PURE__ */ new Map(), current: null });
1958
1954
  }
1959
- const cached = configCache.get(key);
1960
- cached.versions.set(version, c);
1961
- cached.latest = version;
1955
+ const cached = promptCache.get(p.key);
1956
+ cached.versions.set(p.version, {
1957
+ systemPrompt: p.system_prompt,
1958
+ userTemplate: p.user_template
1959
+ });
1960
+ cached.current = p.version;
1962
1961
  }
1963
- } else {
1964
- log2(`Fetch failed: ${resp.statusText}`);
1965
1962
  }
1966
- } catch (e) {
1967
- log2(`Fetch exception: ${e}`);
1963
+ } catch {
1968
1964
  }
1969
1965
  }
1970
- async function fetchSpecificVersion(configKey, version, timeout = SYNC_TIMEOUT) {
1971
- if (!apiKey2) return null;
1966
+ async function fetchPromptABTests(timeout = SYNC_TIMEOUT) {
1967
+ if (!apiKey2) return;
1972
1968
  try {
1973
1969
  const controller = new AbortController();
1974
1970
  const timeoutId = setTimeout(() => controller.abort(), timeout);
1975
- const resp = await fetch(
1976
- `${baseUrl2}/configs/${configKey}/version/${version}`,
1977
- {
1978
- headers: { Authorization: `Bearer ${apiKey2}` },
1979
- signal: controller.signal
1980
- }
1981
- );
1971
+ const resp = await fetch(`${baseUrl2}/prompt-ab-tests`, {
1972
+ headers: { Authorization: `Bearer ${apiKey2}` },
1973
+ signal: controller.signal
1974
+ });
1982
1975
  clearTimeout(timeoutId);
1983
1976
  if (resp.ok) {
1984
- const config = await resp.json();
1985
- if (!configCache.has(configKey)) {
1986
- configCache.set(configKey, { versions: /* @__PURE__ */ new Map(), latest: null });
1977
+ const data = await resp.json();
1978
+ for (const t of data.prompt_ab_tests || []) {
1979
+ if (!promptABCache.has(t.key)) {
1980
+ promptABCache.set(t.key, { versions: /* @__PURE__ */ new Map(), current: null });
1981
+ }
1982
+ const cached = promptABCache.get(t.key);
1983
+ cached.versions.set(t.version, { variants: t.variants });
1984
+ cached.current = t.version;
1987
1985
  }
1988
- configCache.get(configKey).versions.set(version, config);
1989
- return config;
1990
1986
  }
1991
1987
  } catch {
1992
1988
  }
1993
- return null;
1994
1989
  }
1995
- async function get(configKey, sessionId, options = {}) {
1996
- const { version, fallback, debug = false } = options;
1990
+ function replaceVariables(template, variables) {
1991
+ if (!variables) return template;
1992
+ return template.replace(/\{\{(\s*\w+\s*)\}\}/g, (match, varName) => {
1993
+ const key = varName.trim();
1994
+ return key in variables ? String(variables[key]) : match;
1995
+ });
1996
+ }
1997
+ function setPromptContext(ctx) {
1998
+ promptContext = ctx;
1999
+ }
2000
+ function getPromptContext() {
2001
+ const ctx = promptContext;
2002
+ promptContext = null;
2003
+ return ctx;
2004
+ }
2005
+ async function get(promptKey, options = {}) {
2006
+ const { variables, version, debug = false } = options;
1997
2007
  debugMode2 = debug;
1998
2008
  ensureInit();
1999
- log2(
2000
- `get() called: configKey=${configKey}, sessionId=${sessionId}, fallback=${fallback}`
2001
- );
2002
- try {
2003
- let configData = configCache.get(configKey);
2004
- log2(
2005
- `Cache lookup for '${configKey}': ${configData ? "found" : "not found"}`
2009
+ log4(`get() called: promptKey=${promptKey}`);
2010
+ let promptData = promptCache.get(promptKey);
2011
+ if (!promptData) {
2012
+ log4("Not in cache, fetching...");
2013
+ await fetchPrompts(SYNC_TIMEOUT);
2014
+ promptData = promptCache.get(promptKey);
2015
+ }
2016
+ if (!promptData) {
2017
+ throw new Error(
2018
+ `Prompt '${promptKey}' not found. Check that it exists in your Fallom dashboard.`
2006
2019
  );
2007
- if (!configData) {
2008
- log2("Not in cache, fetching...");
2009
- await fetchConfigs(SYNC_TIMEOUT);
2010
- configData = configCache.get(configKey);
2011
- log2(
2012
- `After fetch, cache lookup: ${configData ? "found" : "still not found"}`
2013
- );
2014
- }
2015
- if (!configData) {
2016
- log2(`Config not found, using fallback: ${fallback}`);
2017
- if (fallback) {
2018
- console.warn(
2019
- `[Fallom WARNING] Config '${configKey}' not found, using fallback model: ${fallback}`
2020
- );
2021
- return returnWithTrace(configKey, sessionId, fallback, 0);
2022
- }
2023
- throw new Error(
2024
- `Config '${configKey}' not found. Check that it exists in your Fallom dashboard.`
2025
- );
2026
- }
2027
- let config;
2028
- let targetVersion;
2029
- if (version !== void 0) {
2030
- config = configData.versions.get(version);
2031
- if (!config) {
2032
- config = await fetchSpecificVersion(configKey, version, SYNC_TIMEOUT) || void 0;
2033
- }
2034
- if (!config) {
2035
- if (fallback) {
2036
- console.warn(
2037
- `[Fallom WARNING] Config '${configKey}' version ${version} not found, using fallback: ${fallback}`
2038
- );
2039
- return returnWithTrace(configKey, sessionId, fallback, 0);
2040
- }
2041
- throw new Error(`Config '${configKey}' version ${version} not found.`);
2042
- }
2043
- targetVersion = version;
2044
- } else {
2045
- targetVersion = configData.latest;
2046
- config = configData.versions.get(targetVersion);
2047
- if (!config) {
2048
- if (fallback) {
2049
- console.warn(
2050
- `[Fallom WARNING] Config '${configKey}' has no cached version, using fallback: ${fallback}`
2051
- );
2052
- return returnWithTrace(configKey, sessionId, fallback, 0);
2053
- }
2054
- throw new Error(`Config '${configKey}' has no cached version.`);
2055
- }
2056
- }
2057
- const variantsRaw = config.variants;
2058
- const configVersion = config.version || targetVersion;
2059
- const variants = Array.isArray(variantsRaw) ? variantsRaw : Object.values(variantsRaw);
2060
- log2(
2061
- `Config found! Version: ${configVersion}, Variants: ${JSON.stringify(
2062
- variants
2063
- )}`
2020
+ }
2021
+ const targetVersion = version ?? promptData.current;
2022
+ const content = promptData.versions.get(targetVersion);
2023
+ if (!content) {
2024
+ throw new Error(
2025
+ `Prompt '${promptKey}' version ${targetVersion} not found.`
2064
2026
  );
2065
- const hashBytes = createHash("md5").update(sessionId).digest();
2066
- const hashVal = hashBytes.readUInt32BE(0) % 1e6;
2067
- log2(`Session hash: ${hashVal} (out of 1,000,000)`);
2068
- let cumulative = 0;
2069
- let assignedModel = variants[variants.length - 1].model;
2070
- for (const v of variants) {
2071
- const oldCumulative = cumulative;
2072
- cumulative += v.weight * 1e4;
2073
- log2(
2074
- `Variant ${v.model}: weight=${v.weight}%, range=${oldCumulative}-${cumulative}, hash=${hashVal}, match=${hashVal < cumulative}`
2075
- );
2076
- if (hashVal < cumulative) {
2077
- assignedModel = v.model;
2078
- break;
2079
- }
2080
- }
2081
- log2(`\u2705 Assigned model: ${assignedModel}`);
2082
- return returnWithTrace(configKey, sessionId, assignedModel, configVersion);
2083
- } catch (e) {
2084
- if (e instanceof Error && e.message.includes("not found")) {
2085
- throw e;
2086
- }
2087
- if (fallback) {
2088
- console.warn(
2089
- `[Fallom WARNING] Error getting model for '${configKey}': ${e}. Using fallback: ${fallback}`
2090
- );
2091
- return returnWithTrace(configKey, sessionId, fallback, 0);
2092
- }
2093
- throw e;
2094
2027
  }
2028
+ const system = replaceVariables(content.systemPrompt, variables);
2029
+ const user = replaceVariables(content.userTemplate, variables);
2030
+ setPromptContext({
2031
+ promptKey,
2032
+ promptVersion: targetVersion
2033
+ });
2034
+ log4(`\u2705 Got prompt: ${promptKey} v${targetVersion}`);
2035
+ return {
2036
+ key: promptKey,
2037
+ version: targetVersion,
2038
+ system,
2039
+ user
2040
+ };
2095
2041
  }
2096
- function returnWithTrace(configKey, sessionId, model, version) {
2097
- try {
2098
- setSession(configKey, sessionId);
2099
- } catch {
2042
+ async function getAB(abTestKey, sessionId, options = {}) {
2043
+ const { variables, debug = false } = options;
2044
+ debugMode2 = debug;
2045
+ ensureInit();
2046
+ log4(`getAB() called: abTestKey=${abTestKey}, sessionId=${sessionId}`);
2047
+ let abData = promptABCache.get(abTestKey);
2048
+ if (!abData) {
2049
+ log4("Not in cache, fetching...");
2050
+ await fetchPromptABTests(SYNC_TIMEOUT);
2051
+ abData = promptABCache.get(abTestKey);
2100
2052
  }
2101
- if (version > 0) {
2102
- recordSession(configKey, version, sessionId, model).catch(() => {
2103
- });
2053
+ if (!abData) {
2054
+ throw new Error(
2055
+ `Prompt A/B test '${abTestKey}' not found. Check that it exists in your Fallom dashboard.`
2056
+ );
2104
2057
  }
2105
- return model;
2106
- }
2107
- async function recordSession(configKey, version, sessionId, model) {
2108
- if (!apiKey2) return;
2109
- try {
2110
- const controller = new AbortController();
2111
- const timeoutId = setTimeout(() => controller.abort(), RECORD_TIMEOUT);
2112
- await fetch(`${baseUrl2}/sessions`, {
2113
- method: "POST",
2114
- headers: {
2115
- Authorization: `Bearer ${apiKey2}`,
2116
- "Content-Type": "application/json"
2117
- },
2118
- body: JSON.stringify({
2119
- config_key: configKey,
2120
- config_version: version,
2121
- session_id: sessionId,
2122
- assigned_model: model
2123
- }),
2124
- signal: controller.signal
2125
- });
2126
- clearTimeout(timeoutId);
2127
- } catch {
2058
+ const currentVersion = abData.current;
2059
+ const versionData = abData.versions.get(currentVersion);
2060
+ if (!versionData) {
2061
+ throw new Error(`Prompt A/B test '${abTestKey}' has no current version.`);
2062
+ }
2063
+ const { variants } = versionData;
2064
+ log4(`A/B test '${abTestKey}' has ${variants?.length ?? 0} variants`);
2065
+ log4(`Version data: ${JSON.stringify(versionData, null, 2)}`);
2066
+ if (!variants || variants.length === 0) {
2067
+ throw new Error(
2068
+ `Prompt A/B test '${abTestKey}' has no variants configured.`
2069
+ );
2128
2070
  }
2071
+ const hashBytes = createHash("md5").update(sessionId).digest();
2072
+ const hashVal = hashBytes.readUInt32BE(0) % 1e6;
2073
+ let cumulative = 0;
2074
+ let selectedVariant = variants[variants.length - 1];
2075
+ let selectedIndex = variants.length - 1;
2076
+ for (let i = 0; i < variants.length; i++) {
2077
+ cumulative += variants[i].weight * 1e4;
2078
+ if (hashVal < cumulative) {
2079
+ selectedVariant = variants[i];
2080
+ selectedIndex = i;
2081
+ break;
2082
+ }
2083
+ }
2084
+ const promptKey = selectedVariant.prompt_key;
2085
+ const promptVersion = selectedVariant.prompt_version;
2086
+ let promptData = promptCache.get(promptKey);
2087
+ if (!promptData) {
2088
+ await fetchPrompts(SYNC_TIMEOUT);
2089
+ promptData = promptCache.get(promptKey);
2090
+ }
2091
+ if (!promptData) {
2092
+ throw new Error(
2093
+ `Prompt '${promptKey}' (from A/B test '${abTestKey}') not found.`
2094
+ );
2095
+ }
2096
+ const targetVersion = promptVersion ?? promptData.current;
2097
+ const content = promptData.versions.get(targetVersion);
2098
+ if (!content) {
2099
+ throw new Error(
2100
+ `Prompt '${promptKey}' version ${targetVersion} not found.`
2101
+ );
2102
+ }
2103
+ const system = replaceVariables(content.systemPrompt, variables);
2104
+ const user = replaceVariables(content.userTemplate, variables);
2105
+ setPromptContext({
2106
+ promptKey,
2107
+ promptVersion: targetVersion,
2108
+ abTestKey,
2109
+ variantIndex: selectedIndex
2110
+ });
2111
+ log4(
2112
+ `\u2705 Got prompt from A/B: ${promptKey} v${targetVersion} (variant ${selectedIndex})`
2113
+ );
2114
+ return {
2115
+ key: promptKey,
2116
+ version: targetVersion,
2117
+ system,
2118
+ user,
2119
+ abTestKey,
2120
+ variantIndex: selectedIndex
2121
+ };
2122
+ }
2123
+ function clearPromptContext() {
2124
+ promptContext = null;
2129
2125
  }
2130
2126
 
2131
2127
  // src/init.ts
@@ -2139,11 +2135,11 @@ async function init4(options = {}) {
2139
2135
  captureContent: options.captureContent,
2140
2136
  debug: options.debug
2141
2137
  });
2142
- init3({
2138
+ init({
2143
2139
  apiKey: options.apiKey,
2144
2140
  baseUrl: configsUrl
2145
2141
  });
2146
- init({
2142
+ init3({
2147
2143
  apiKey: options.apiKey,
2148
2144
  baseUrl: promptsUrl
2149
2145
  });
@@ -2151,9 +2147,9 @@ async function init4(options = {}) {
2151
2147
 
2152
2148
  // src/mastra.ts
2153
2149
  import { ExportResultCode } from "@opentelemetry/core";
2154
- var promptContext = {};
2150
+ var promptContext2 = {};
2155
2151
  function setMastraPrompt(promptKey, version) {
2156
- promptContext = {
2152
+ promptContext2 = {
2157
2153
  promptKey,
2158
2154
  promptVersion: version,
2159
2155
  promptAbTestKey: void 0,
@@ -2161,7 +2157,7 @@ function setMastraPrompt(promptKey, version) {
2161
2157
  };
2162
2158
  }
2163
2159
  function setMastraPromptAB(abTestKey, variantIndex) {
2164
- promptContext = {
2160
+ promptContext2 = {
2165
2161
  promptKey: void 0,
2166
2162
  promptVersion: void 0,
2167
2163
  promptAbTestKey: abTestKey,
@@ -2169,7 +2165,7 @@ function setMastraPromptAB(abTestKey, variantIndex) {
2169
2165
  };
2170
2166
  }
2171
2167
  function clearMastraPrompt() {
2172
- promptContext = {};
2168
+ promptContext2 = {};
2173
2169
  }
2174
2170
  var FallomExporter = class {
2175
2171
  constructor(options = {}) {
@@ -2177,9 +2173,13 @@ var FallomExporter = class {
2177
2173
  this.apiKey = options.apiKey ?? process.env.FALLOM_API_KEY ?? "";
2178
2174
  this.baseUrl = options.baseUrl ?? "https://traces.fallom.com";
2179
2175
  this.debug = options.debug ?? false;
2180
- console.log("[FallomExporter] Constructor called, debug:", this.debug);
2181
- console.log("[FallomExporter] API key present:", !!this.apiKey);
2182
- console.log("[FallomExporter] Base URL:", this.baseUrl);
2176
+ this.session = options.session;
2177
+ if (this.debug) {
2178
+ console.log("[FallomExporter] Constructor called");
2179
+ console.log("[FallomExporter] API key present:", !!this.apiKey);
2180
+ console.log("[FallomExporter] Base URL:", this.baseUrl);
2181
+ console.log("[FallomExporter] Session:", this.session);
2182
+ }
2183
2183
  if (!this.apiKey) {
2184
2184
  console.warn(
2185
2185
  "[FallomExporter] No API key provided. Set FALLOM_API_KEY env var or pass apiKey option."
@@ -2201,10 +2201,10 @@ var FallomExporter = class {
2201
2201
  }
2202
2202
  this.log(`Exporting ${spans.length} spans...`);
2203
2203
  if (this.debug) {
2204
- for (const span2 of spans) {
2205
- this.log(` - ${span2.name}`, {
2204
+ for (const span of spans) {
2205
+ this.log(` - ${span.name}`, {
2206
2206
  attributes: Object.fromEntries(
2207
- Object.entries(span2.attributes).filter(
2207
+ Object.entries(span.attributes).filter(
2208
2208
  ([k]) => k.startsWith("gen_ai") || k.startsWith("llm")
2209
2209
  )
2210
2210
  )
@@ -2240,33 +2240,32 @@ var FallomExporter = class {
2240
2240
  * Send spans to Fallom's OTLP endpoint.
2241
2241
  */
2242
2242
  async sendSpans(spans) {
2243
- const session = getSession();
2244
2243
  const resourceSpans = this.spansToOtlpJson(spans);
2245
2244
  const headers = {
2246
2245
  "Content-Type": "application/json",
2247
2246
  Authorization: `Bearer ${this.apiKey}`
2248
2247
  };
2249
- if (session?.configKey) {
2250
- headers["X-Fallom-Config-Key"] = session.configKey;
2248
+ if (this.session?.configKey) {
2249
+ headers["X-Fallom-Config-Key"] = this.session.configKey;
2251
2250
  }
2252
- if (session?.sessionId) {
2253
- headers["X-Fallom-Session-Id"] = session.sessionId;
2251
+ if (this.session?.sessionId) {
2252
+ headers["X-Fallom-Session-Id"] = this.session.sessionId;
2254
2253
  }
2255
- if (session?.customerId) {
2256
- headers["X-Fallom-Customer-Id"] = session.customerId;
2254
+ if (this.session?.customerId) {
2255
+ headers["X-Fallom-Customer-Id"] = this.session.customerId;
2257
2256
  }
2258
- if (promptContext.promptKey) {
2259
- headers["X-Fallom-Prompt-Key"] = promptContext.promptKey;
2257
+ if (promptContext2.promptKey) {
2258
+ headers["X-Fallom-Prompt-Key"] = promptContext2.promptKey;
2260
2259
  }
2261
- if (promptContext.promptVersion !== void 0) {
2262
- headers["X-Fallom-Prompt-Version"] = String(promptContext.promptVersion);
2260
+ if (promptContext2.promptVersion !== void 0) {
2261
+ headers["X-Fallom-Prompt-Version"] = String(promptContext2.promptVersion);
2263
2262
  }
2264
- if (promptContext.promptAbTestKey) {
2265
- headers["X-Fallom-Prompt-AB-Test"] = promptContext.promptAbTestKey;
2263
+ if (promptContext2.promptAbTestKey) {
2264
+ headers["X-Fallom-Prompt-AB-Test"] = promptContext2.promptAbTestKey;
2266
2265
  }
2267
- if (promptContext.promptVariantIndex !== void 0) {
2266
+ if (promptContext2.promptVariantIndex !== void 0) {
2268
2267
  headers["X-Fallom-Prompt-Variant"] = String(
2269
- promptContext.promptVariantIndex
2268
+ promptContext2.promptVariantIndex
2270
2269
  );
2271
2270
  }
2272
2271
  const endpoint = `${this.baseUrl}/v1/traces`;
@@ -2290,12 +2289,12 @@ var FallomExporter = class {
2290
2289
  */
2291
2290
  spansToOtlpJson(spans) {
2292
2291
  const resourceMap = /* @__PURE__ */ new Map();
2293
- for (const span2 of spans) {
2294
- const resourceKey = JSON.stringify(span2.resource.attributes);
2292
+ for (const span of spans) {
2293
+ const resourceKey = JSON.stringify(span.resource.attributes);
2295
2294
  if (!resourceMap.has(resourceKey)) {
2296
2295
  resourceMap.set(resourceKey, []);
2297
2296
  }
2298
- resourceMap.get(resourceKey).push(span2);
2297
+ resourceMap.get(resourceKey).push(span);
2299
2298
  }
2300
2299
  const resourceSpans = [];
2301
2300
  for (const [_resourceKey, resourceSpanList] of resourceMap) {
@@ -2310,7 +2309,7 @@ var FallomExporter = class {
2310
2309
  name: firstSpan.instrumentationLibrary.name,
2311
2310
  version: firstSpan.instrumentationLibrary.version
2312
2311
  },
2313
- spans: resourceSpanList.map((span2) => this.spanToOtlp(span2))
2312
+ spans: resourceSpanList.map((span) => this.spanToOtlp(span))
2314
2313
  }
2315
2314
  ]
2316
2315
  });
@@ -2320,21 +2319,21 @@ var FallomExporter = class {
2320
2319
  /**
2321
2320
  * Convert a single span to OTLP format.
2322
2321
  */
2323
- spanToOtlp(span2) {
2322
+ spanToOtlp(span) {
2324
2323
  return {
2325
- traceId: span2.spanContext().traceId,
2326
- spanId: span2.spanContext().spanId,
2327
- parentSpanId: span2.parentSpanId,
2328
- name: span2.name,
2329
- kind: span2.kind,
2330
- startTimeUnixNano: this.hrTimeToNanos(span2.startTime),
2331
- endTimeUnixNano: this.hrTimeToNanos(span2.endTime),
2332
- attributes: this.attributesToOtlp(span2.attributes),
2324
+ traceId: span.spanContext().traceId,
2325
+ spanId: span.spanContext().spanId,
2326
+ parentSpanId: span.parentSpanId,
2327
+ name: span.name,
2328
+ kind: span.kind,
2329
+ startTimeUnixNano: this.hrTimeToNanos(span.startTime),
2330
+ endTimeUnixNano: this.hrTimeToNanos(span.endTime),
2331
+ attributes: this.attributesToOtlp(span.attributes),
2333
2332
  status: {
2334
- code: span2.status.code,
2335
- message: span2.status.message
2333
+ code: span.status.code,
2334
+ message: span.status.message
2336
2335
  },
2337
- events: span2.events.map((event) => ({
2336
+ events: span.events.map((event) => ({
2338
2337
  timeUnixNano: this.hrTimeToNanos(event.time),
2339
2338
  name: event.name,
2340
2339
  attributes: this.attributesToOtlp(event.attributes || {})
@@ -2389,15 +2388,18 @@ var index_default = {
2389
2388
  init: init4,
2390
2389
  trace: trace_exports,
2391
2390
  models: models_exports,
2392
- prompts: prompts_exports
2391
+ prompts: prompts_exports,
2392
+ session
2393
2393
  };
2394
2394
  export {
2395
2395
  FallomExporter,
2396
+ FallomSession,
2396
2397
  clearMastraPrompt,
2397
2398
  index_default as default,
2398
2399
  init4 as init,
2399
2400
  models_exports as models,
2400
2401
  prompts_exports as prompts,
2402
+ session,
2401
2403
  setMastraPrompt,
2402
2404
  setMastraPromptAB,
2403
2405
  trace_exports as trace