@fallom/trace 0.1.12 → 0.2.1

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
@@ -20,249 +20,248 @@ var __copyProps = (to, from, except, desc) => {
20
20
  };
21
21
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
22
 
23
- // src/prompts.ts
24
- var prompts_exports = {};
25
- __export(prompts_exports, {
26
- clearPromptContext: () => clearPromptContext,
23
+ // src/models.ts
24
+ var models_exports = {};
25
+ __export(models_exports, {
27
26
  get: () => get,
28
- getAB: () => getAB,
29
- getPromptContext: () => getPromptContext,
30
- init: () => init
27
+ init: () => init2
31
28
  });
32
- function log(msg) {
33
- if (debugMode) {
34
- console.log(`[Fallom Prompts] ${msg}`);
29
+ function log4(msg) {
30
+ if (debugMode2) {
31
+ console.log(`[Fallom] ${msg}`);
35
32
  }
36
33
  }
37
- function init(options = {}) {
38
- apiKey = options.apiKey || process.env.FALLOM_API_KEY || null;
39
- baseUrl = options.baseUrl || process.env.FALLOM_PROMPTS_URL || process.env.FALLOM_BASE_URL || "https://prompts.fallom.com";
40
- initialized = true;
41
- if (!apiKey) {
34
+ function init2(options = {}) {
35
+ apiKey2 = options.apiKey || process.env.FALLOM_API_KEY || null;
36
+ baseUrl2 = options.baseUrl || process.env.FALLOM_CONFIGS_URL || process.env.FALLOM_BASE_URL || "https://configs.fallom.com";
37
+ initialized2 = true;
38
+ if (!apiKey2) {
42
39
  return;
43
40
  }
44
- fetchAll().catch(() => {
41
+ fetchConfigs().catch(() => {
45
42
  });
46
43
  if (!syncInterval) {
47
44
  syncInterval = setInterval(() => {
48
- fetchAll().catch(() => {
45
+ fetchConfigs().catch(() => {
49
46
  });
50
47
  }, 3e4);
51
48
  syncInterval.unref();
52
49
  }
53
50
  }
54
51
  function ensureInit() {
55
- if (!initialized) {
52
+ if (!initialized2) {
56
53
  try {
57
- init();
54
+ init2();
58
55
  } catch {
59
56
  }
60
57
  }
61
58
  }
62
- async function fetchAll() {
63
- await Promise.all([fetchPrompts(), fetchPromptABTests()]);
64
- }
65
- async function fetchPrompts(timeout = SYNC_TIMEOUT) {
66
- if (!apiKey) return;
59
+ async function fetchConfigs(timeout = SYNC_TIMEOUT) {
60
+ if (!apiKey2) {
61
+ log4("_fetchConfigs: No API key, skipping");
62
+ return;
63
+ }
67
64
  try {
65
+ log4(`Fetching configs from ${baseUrl2}/configs`);
68
66
  const controller = new AbortController();
69
67
  const timeoutId = setTimeout(() => controller.abort(), timeout);
70
- const resp = await fetch(`${baseUrl}/prompts`, {
71
- headers: { Authorization: `Bearer ${apiKey}` },
68
+ const resp = await fetch(`${baseUrl2}/configs`, {
69
+ headers: { Authorization: `Bearer ${apiKey2}` },
72
70
  signal: controller.signal
73
71
  });
74
72
  clearTimeout(timeoutId);
73
+ log4(`Response status: ${resp.status}`);
75
74
  if (resp.ok) {
76
75
  const data = await resp.json();
77
- for (const p of data.prompts || []) {
78
- if (!promptCache.has(p.key)) {
79
- promptCache.set(p.key, { versions: /* @__PURE__ */ new Map(), current: null });
76
+ const configs = data.configs || [];
77
+ log4(`Got ${configs.length} configs: ${configs.map((c) => c.key)}`);
78
+ for (const c of configs) {
79
+ const key = c.key;
80
+ const version = c.version || 1;
81
+ log4(`Config '${key}' v${version}: ${JSON.stringify(c.variants)}`);
82
+ if (!configCache.has(key)) {
83
+ configCache.set(key, { versions: /* @__PURE__ */ new Map(), latest: null });
80
84
  }
81
- const cached = promptCache.get(p.key);
82
- cached.versions.set(p.version, {
83
- systemPrompt: p.system_prompt,
84
- userTemplate: p.user_template
85
- });
86
- cached.current = p.version;
85
+ const cached = configCache.get(key);
86
+ cached.versions.set(version, c);
87
+ cached.latest = version;
87
88
  }
89
+ } else {
90
+ log4(`Fetch failed: ${resp.statusText}`);
88
91
  }
89
- } catch {
92
+ } catch (e) {
93
+ log4(`Fetch exception: ${e}`);
90
94
  }
91
95
  }
92
- async function fetchPromptABTests(timeout = SYNC_TIMEOUT) {
93
- if (!apiKey) return;
96
+ async function fetchSpecificVersion(configKey, version, timeout = SYNC_TIMEOUT) {
97
+ if (!apiKey2) return null;
94
98
  try {
95
99
  const controller = new AbortController();
96
100
  const timeoutId = setTimeout(() => controller.abort(), timeout);
97
- const resp = await fetch(`${baseUrl}/prompt-ab-tests`, {
98
- headers: { Authorization: `Bearer ${apiKey}` },
99
- signal: controller.signal
100
- });
101
+ const resp = await fetch(
102
+ `${baseUrl2}/configs/${configKey}/version/${version}`,
103
+ {
104
+ headers: { Authorization: `Bearer ${apiKey2}` },
105
+ signal: controller.signal
106
+ }
107
+ );
101
108
  clearTimeout(timeoutId);
102
109
  if (resp.ok) {
103
- const data = await resp.json();
104
- for (const t of data.prompt_ab_tests || []) {
105
- if (!promptABCache.has(t.key)) {
106
- promptABCache.set(t.key, { versions: /* @__PURE__ */ new Map(), current: null });
107
- }
108
- const cached = promptABCache.get(t.key);
109
- cached.versions.set(t.version, { variants: t.variants });
110
- cached.current = t.version;
110
+ const config = await resp.json();
111
+ if (!configCache.has(configKey)) {
112
+ configCache.set(configKey, { versions: /* @__PURE__ */ new Map(), latest: null });
111
113
  }
114
+ configCache.get(configKey).versions.set(version, config);
115
+ return config;
112
116
  }
113
117
  } catch {
114
118
  }
119
+ return null;
115
120
  }
116
- function replaceVariables(template, variables) {
117
- if (!variables) return template;
118
- return template.replace(/\{\{(\s*\w+\s*)\}\}/g, (match, varName) => {
119
- const key = varName.trim();
120
- return key in variables ? String(variables[key]) : match;
121
- });
122
- }
123
- function setPromptContext(ctx) {
124
- promptContext = ctx;
125
- }
126
- function getPromptContext() {
127
- const ctx = promptContext;
128
- promptContext = null;
129
- return ctx;
130
- }
131
- async function get(promptKey, options = {}) {
132
- const { variables, version, debug = false } = options;
133
- debugMode = debug;
134
- ensureInit();
135
- log(`get() called: promptKey=${promptKey}`);
136
- let promptData = promptCache.get(promptKey);
137
- if (!promptData) {
138
- log("Not in cache, fetching...");
139
- await fetchPrompts(SYNC_TIMEOUT);
140
- promptData = promptCache.get(promptKey);
141
- }
142
- if (!promptData) {
143
- throw new Error(
144
- `Prompt '${promptKey}' not found. Check that it exists in your Fallom dashboard.`
145
- );
146
- }
147
- const targetVersion = version ?? promptData.current;
148
- const content = promptData.versions.get(targetVersion);
149
- if (!content) {
150
- throw new Error(
151
- `Prompt '${promptKey}' version ${targetVersion} not found.`
152
- );
153
- }
154
- const system = replaceVariables(content.systemPrompt, variables);
155
- const user = replaceVariables(content.userTemplate, variables);
156
- setPromptContext({
157
- promptKey,
158
- promptVersion: targetVersion
159
- });
160
- log(`\u2705 Got prompt: ${promptKey} v${targetVersion}`);
161
- return {
162
- key: promptKey,
163
- version: targetVersion,
164
- system,
165
- user
166
- };
167
- }
168
- async function getAB(abTestKey, sessionId, options = {}) {
169
- const { variables, debug = false } = options;
170
- debugMode = debug;
121
+ async function get(configKey, sessionId, options = {}) {
122
+ const { version, fallback, debug = false } = options;
123
+ debugMode2 = debug;
171
124
  ensureInit();
172
- log(`getAB() called: abTestKey=${abTestKey}, sessionId=${sessionId}`);
173
- let abData = promptABCache.get(abTestKey);
174
- if (!abData) {
175
- log("Not in cache, fetching...");
176
- await fetchPromptABTests(SYNC_TIMEOUT);
177
- abData = promptABCache.get(abTestKey);
178
- }
179
- if (!abData) {
180
- throw new Error(
181
- `Prompt A/B test '${abTestKey}' not found. Check that it exists in your Fallom dashboard.`
182
- );
183
- }
184
- const currentVersion = abData.current;
185
- const versionData = abData.versions.get(currentVersion);
186
- if (!versionData) {
187
- throw new Error(`Prompt A/B test '${abTestKey}' has no current version.`);
188
- }
189
- const { variants } = versionData;
190
- log(`A/B test '${abTestKey}' has ${variants?.length ?? 0} variants`);
191
- log(`Version data: ${JSON.stringify(versionData, null, 2)}`);
192
- if (!variants || variants.length === 0) {
193
- throw new Error(
194
- `Prompt A/B test '${abTestKey}' has no variants configured.`
125
+ log4(
126
+ `get() called: configKey=${configKey}, sessionId=${sessionId}, fallback=${fallback}`
127
+ );
128
+ try {
129
+ let configData = configCache.get(configKey);
130
+ log4(
131
+ `Cache lookup for '${configKey}': ${configData ? "found" : "not found"}`
195
132
  );
196
- }
197
- const hashBytes = (0, import_crypto.createHash)("md5").update(sessionId).digest();
198
- const hashVal = hashBytes.readUInt32BE(0) % 1e6;
199
- let cumulative = 0;
200
- let selectedVariant = variants[variants.length - 1];
201
- let selectedIndex = variants.length - 1;
202
- for (let i = 0; i < variants.length; i++) {
203
- cumulative += variants[i].weight * 1e4;
204
- if (hashVal < cumulative) {
205
- selectedVariant = variants[i];
206
- selectedIndex = i;
207
- break;
133
+ if (!configData) {
134
+ log4("Not in cache, fetching...");
135
+ await fetchConfigs(SYNC_TIMEOUT);
136
+ configData = configCache.get(configKey);
137
+ log4(
138
+ `After fetch, cache lookup: ${configData ? "found" : "still not found"}`
139
+ );
208
140
  }
209
- }
210
- const promptKey = selectedVariant.prompt_key;
211
- const promptVersion = selectedVariant.prompt_version;
212
- let promptData = promptCache.get(promptKey);
213
- if (!promptData) {
214
- await fetchPrompts(SYNC_TIMEOUT);
215
- promptData = promptCache.get(promptKey);
216
- }
217
- if (!promptData) {
218
- throw new Error(
219
- `Prompt '${promptKey}' (from A/B test '${abTestKey}') not found.`
141
+ if (!configData) {
142
+ log4(`Config not found, using fallback: ${fallback}`);
143
+ if (fallback) {
144
+ console.warn(
145
+ `[Fallom WARNING] Config '${configKey}' not found, using fallback model: ${fallback}`
146
+ );
147
+ return returnModel(configKey, sessionId, fallback, 0);
148
+ }
149
+ throw new Error(
150
+ `Config '${configKey}' not found. Check that it exists in your Fallom dashboard.`
151
+ );
152
+ }
153
+ let config;
154
+ let targetVersion;
155
+ if (version !== void 0) {
156
+ config = configData.versions.get(version);
157
+ if (!config) {
158
+ config = await fetchSpecificVersion(configKey, version, SYNC_TIMEOUT) || void 0;
159
+ }
160
+ if (!config) {
161
+ if (fallback) {
162
+ console.warn(
163
+ `[Fallom WARNING] Config '${configKey}' version ${version} not found, using fallback: ${fallback}`
164
+ );
165
+ return returnModel(configKey, sessionId, fallback, 0);
166
+ }
167
+ throw new Error(`Config '${configKey}' version ${version} not found.`);
168
+ }
169
+ targetVersion = version;
170
+ } else {
171
+ targetVersion = configData.latest;
172
+ config = configData.versions.get(targetVersion);
173
+ if (!config) {
174
+ if (fallback) {
175
+ console.warn(
176
+ `[Fallom WARNING] Config '${configKey}' has no cached version, using fallback: ${fallback}`
177
+ );
178
+ return returnModel(configKey, sessionId, fallback, 0);
179
+ }
180
+ throw new Error(`Config '${configKey}' has no cached version.`);
181
+ }
182
+ }
183
+ const variantsRaw = config.variants;
184
+ const configVersion = config.version || targetVersion;
185
+ const variants = Array.isArray(variantsRaw) ? variantsRaw : Object.values(variantsRaw);
186
+ log4(
187
+ `Config found! Version: ${configVersion}, Variants: ${JSON.stringify(
188
+ variants
189
+ )}`
220
190
  );
191
+ const hashBytes = (0, import_crypto.createHash)("md5").update(sessionId).digest();
192
+ const hashVal = hashBytes.readUInt32BE(0) % 1e6;
193
+ log4(`Session hash: ${hashVal} (out of 1,000,000)`);
194
+ let cumulative = 0;
195
+ let assignedModel = variants[variants.length - 1].model;
196
+ for (const v of variants) {
197
+ const oldCumulative = cumulative;
198
+ cumulative += v.weight * 1e4;
199
+ log4(
200
+ `Variant ${v.model}: weight=${v.weight}%, range=${oldCumulative}-${cumulative}, hash=${hashVal}, match=${hashVal < cumulative}`
201
+ );
202
+ if (hashVal < cumulative) {
203
+ assignedModel = v.model;
204
+ break;
205
+ }
206
+ }
207
+ log4(`\u2705 Assigned model: ${assignedModel}`);
208
+ return returnModel(configKey, sessionId, assignedModel, configVersion);
209
+ } catch (e) {
210
+ if (e instanceof Error && e.message.includes("not found")) {
211
+ throw e;
212
+ }
213
+ if (fallback) {
214
+ console.warn(
215
+ `[Fallom WARNING] Error getting model for '${configKey}': ${e}. Using fallback: ${fallback}`
216
+ );
217
+ return returnModel(configKey, sessionId, fallback, 0);
218
+ }
219
+ throw e;
221
220
  }
222
- const targetVersion = promptVersion ?? promptData.current;
223
- const content = promptData.versions.get(targetVersion);
224
- if (!content) {
225
- throw new Error(
226
- `Prompt '${promptKey}' version ${targetVersion} not found.`
227
- );
221
+ }
222
+ function returnModel(configKey, sessionId, model, version) {
223
+ if (version > 0) {
224
+ recordSession(configKey, version, sessionId, model).catch(() => {
225
+ });
228
226
  }
229
- const system = replaceVariables(content.systemPrompt, variables);
230
- const user = replaceVariables(content.userTemplate, variables);
231
- setPromptContext({
232
- promptKey,
233
- promptVersion: targetVersion,
234
- abTestKey,
235
- variantIndex: selectedIndex
236
- });
237
- log(
238
- `\u2705 Got prompt from A/B: ${promptKey} v${targetVersion} (variant ${selectedIndex})`
239
- );
240
- return {
241
- key: promptKey,
242
- version: targetVersion,
243
- system,
244
- user,
245
- abTestKey,
246
- variantIndex: selectedIndex
247
- };
227
+ return model;
248
228
  }
249
- function clearPromptContext() {
250
- promptContext = null;
229
+ async function recordSession(configKey, version, sessionId, model) {
230
+ if (!apiKey2) return;
231
+ try {
232
+ const controller = new AbortController();
233
+ const timeoutId = setTimeout(() => controller.abort(), RECORD_TIMEOUT);
234
+ await fetch(`${baseUrl2}/sessions`, {
235
+ method: "POST",
236
+ headers: {
237
+ Authorization: `Bearer ${apiKey2}`,
238
+ "Content-Type": "application/json"
239
+ },
240
+ body: JSON.stringify({
241
+ config_key: configKey,
242
+ config_version: version,
243
+ session_id: sessionId,
244
+ assigned_model: model
245
+ }),
246
+ signal: controller.signal
247
+ });
248
+ clearTimeout(timeoutId);
249
+ } catch {
250
+ }
251
251
  }
252
- var import_crypto, apiKey, baseUrl, initialized, syncInterval, debugMode, promptCache, promptABCache, promptContext, SYNC_TIMEOUT;
253
- var init_prompts = __esm({
254
- "src/prompts.ts"() {
252
+ var import_crypto, apiKey2, baseUrl2, initialized2, syncInterval, debugMode2, configCache, SYNC_TIMEOUT, RECORD_TIMEOUT;
253
+ var init_models = __esm({
254
+ "src/models.ts"() {
255
255
  "use strict";
256
256
  import_crypto = require("crypto");
257
- apiKey = null;
258
- baseUrl = "https://prompts.fallom.com";
259
- initialized = false;
257
+ apiKey2 = null;
258
+ baseUrl2 = "https://configs.fallom.com";
259
+ initialized2 = false;
260
260
  syncInterval = null;
261
- debugMode = false;
262
- promptCache = /* @__PURE__ */ new Map();
263
- promptABCache = /* @__PURE__ */ new Map();
264
- promptContext = null;
261
+ debugMode2 = false;
262
+ configCache = /* @__PURE__ */ new Map();
265
263
  SYNC_TIMEOUT = 2e3;
264
+ RECORD_TIMEOUT = 1e3;
266
265
  }
267
266
  });
268
267
 
@@ -270,11 +269,13 @@ var init_prompts = __esm({
270
269
  var index_exports = {};
271
270
  __export(index_exports, {
272
271
  FallomExporter: () => FallomExporter,
272
+ FallomSession: () => FallomSession,
273
273
  clearMastraPrompt: () => clearMastraPrompt,
274
274
  default: () => index_default,
275
275
  init: () => init4,
276
276
  models: () => models_exports,
277
277
  prompts: () => prompts_exports,
278
+ session: () => session,
278
279
  setMastraPrompt: () => setMastraPrompt,
279
280
  setMastraPromptAB: () => setMastraPromptAB,
280
281
  trace: () => trace_exports
@@ -284,19 +285,13 @@ module.exports = __toCommonJS(index_exports);
284
285
  // src/trace.ts
285
286
  var trace_exports = {};
286
287
  __export(trace_exports, {
287
- clearSession: () => clearSession,
288
- getSession: () => getSession,
289
- init: () => init2,
290
- runWithSession: () => runWithSession,
291
- setSession: () => setSession,
292
- shutdown: () => shutdown,
293
- span: () => span,
294
- wrapAISDK: () => wrapAISDK,
295
- wrapAnthropic: () => wrapAnthropic,
296
- wrapGoogleAI: () => wrapGoogleAI,
297
- wrapMastraAgent: () => wrapMastraAgent,
298
- wrapOpenAI: () => wrapOpenAI
288
+ FallomSession: () => FallomSession,
289
+ init: () => init,
290
+ session: () => session,
291
+ shutdown: () => shutdown
299
292
  });
293
+
294
+ // src/trace/core.ts
300
295
  var import_async_hooks = require("async_hooks");
301
296
  var import_sdk_node = require("@opentelemetry/sdk-node");
302
297
  var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
@@ -898,40 +893,39 @@ var Resource = (
898
893
  })()
899
894
  );
900
895
 
901
- // src/trace.ts
902
- var sessionStorage = new import_async_hooks.AsyncLocalStorage();
903
- var fallbackSession = null;
904
- var apiKey2 = null;
905
- var baseUrl2 = "https://traces.fallom.com";
906
- var initialized2 = false;
896
+ // src/trace/core.ts
897
+ var traceContextStorage = new import_async_hooks.AsyncLocalStorage();
898
+ var fallbackTraceContext = null;
899
+ var apiKey = null;
900
+ var baseUrl = "https://traces.fallom.com";
901
+ var initialized = false;
907
902
  var captureContent = true;
908
- var debugMode2 = false;
903
+ var debugMode = false;
909
904
  var sdk = null;
910
- function log2(...args) {
911
- if (debugMode2) console.log("[Fallom]", ...args);
905
+ function log(...args) {
906
+ if (debugMode) console.log("[Fallom]", ...args);
912
907
  }
913
- var fallomSpanProcessor = {
914
- onStart(span2, _parentContext) {
915
- log2("\u{1F4CD} Span started:", span2.name || "unknown");
916
- const ctx = sessionStorage.getStore() || fallbackSession;
917
- if (ctx) {
918
- span2.setAttribute("fallom.config_key", ctx.configKey);
919
- span2.setAttribute("fallom.session_id", ctx.sessionId);
920
- if (ctx.customerId) {
921
- span2.setAttribute("fallom.customer_id", ctx.customerId);
922
- }
923
- log2(
924
- " Added session context:",
925
- ctx.configKey,
926
- ctx.sessionId,
927
- ctx.customerId
928
- );
929
- } else {
930
- log2(" No session context available");
931
- }
908
+ function getTraceContextStorage() {
909
+ return traceContextStorage;
910
+ }
911
+ function getFallbackTraceContext() {
912
+ return fallbackTraceContext;
913
+ }
914
+ function isInitialized() {
915
+ return initialized;
916
+ }
917
+ function shouldCaptureContent() {
918
+ return captureContent;
919
+ }
920
+ function isDebugMode() {
921
+ return debugMode;
922
+ }
923
+ var fallomSpanProcessor = {
924
+ onStart(span, _parentContext) {
925
+ log("\u{1F4CD} Span started:", span.name || "unknown");
932
926
  },
933
- onEnd(span2) {
934
- log2("\u2705 Span ended:", span2.name, "duration:", span2.duration);
927
+ onEnd(span) {
928
+ log("\u2705 Span ended:", span.name, "duration:", span.duration);
935
929
  },
936
930
  shutdown() {
937
931
  return Promise.resolve();
@@ -940,47 +934,6 @@ var fallomSpanProcessor = {
940
934
  return Promise.resolve();
941
935
  }
942
936
  };
943
- async function init2(options = {}) {
944
- if (initialized2) return;
945
- debugMode2 = options.debug ?? false;
946
- log2("\u{1F680} Initializing Fallom tracing...");
947
- apiKey2 = options.apiKey || process.env.FALLOM_API_KEY || null;
948
- baseUrl2 = options.baseUrl || process.env.FALLOM_TRACES_URL || process.env.FALLOM_BASE_URL || "https://traces.fallom.com";
949
- const envCapture = process.env.FALLOM_CAPTURE_CONTENT?.toLowerCase();
950
- if (envCapture === "false" || envCapture === "0" || envCapture === "no") {
951
- captureContent = false;
952
- } else {
953
- captureContent = options.captureContent ?? true;
954
- }
955
- if (!apiKey2) {
956
- throw new Error(
957
- "No API key provided. Set FALLOM_API_KEY environment variable or pass apiKey parameter."
958
- );
959
- }
960
- initialized2 = true;
961
- log2("\u{1F4E1} Exporter URL:", `${baseUrl2}/v1/traces`);
962
- const exporter = new import_exporter_trace_otlp_http.OTLPTraceExporter({
963
- url: `${baseUrl2}/v1/traces`,
964
- headers: {
965
- Authorization: `Bearer ${apiKey2}`
966
- }
967
- });
968
- const instrumentations = await getInstrumentations();
969
- log2("\u{1F527} Loaded instrumentations:", instrumentations.length);
970
- sdk = new import_sdk_node.NodeSDK({
971
- resource: new Resource({
972
- "service.name": "fallom-traced-app"
973
- }),
974
- traceExporter: exporter,
975
- spanProcessor: fallomSpanProcessor,
976
- instrumentations
977
- });
978
- sdk.start();
979
- log2("\u2705 SDK started");
980
- process.on("SIGTERM", () => {
981
- sdk?.shutdown().catch(console.error);
982
- });
983
- }
984
937
  async function getInstrumentations() {
985
938
  const instrumentations = [];
986
939
  await tryAddInstrumentation(
@@ -1028,82 +981,97 @@ async function tryAddInstrumentation(instrumentations, pkg, className) {
1028
981
  instrumentations.push(
1029
982
  new InstrumentationClass({ traceContent: captureContent })
1030
983
  );
1031
- log2(` \u2705 Loaded ${pkg}`);
984
+ log(` \u2705 Loaded ${pkg}`);
1032
985
  } else {
1033
- log2(
986
+ log(
1034
987
  ` \u26A0\uFE0F ${pkg} loaded but ${className} not found. Available:`,
1035
988
  Object.keys(mod)
1036
989
  );
1037
990
  }
1038
- } catch (e) {
1039
- log2(` \u274C ${pkg} not installed`);
1040
- }
1041
- }
1042
- function setSession(configKey, sessionId, customerId) {
1043
- const store = sessionStorage.getStore();
1044
- if (store) {
1045
- store.configKey = configKey;
1046
- store.sessionId = sessionId;
1047
- store.customerId = customerId;
1048
- }
1049
- fallbackSession = { configKey, sessionId, customerId };
1050
- }
1051
- function runWithSession(configKey, sessionId, customerIdOrFn, fn) {
1052
- if (typeof customerIdOrFn === "function") {
1053
- return sessionStorage.run({ configKey, sessionId }, customerIdOrFn);
991
+ } catch {
992
+ log(` \u274C ${pkg} not installed`);
1054
993
  }
1055
- return sessionStorage.run(
1056
- { configKey, sessionId, customerId: customerIdOrFn },
1057
- fn
1058
- );
1059
- }
1060
- function getSession() {
1061
- return sessionStorage.getStore() || fallbackSession || void 0;
1062
- }
1063
- function clearSession() {
1064
- fallbackSession = null;
1065
994
  }
1066
- function span(data, options = {}) {
1067
- if (!initialized2) {
1068
- throw new Error("Fallom not initialized. Call trace.init() first.");
995
+ async function init(options = {}) {
996
+ if (initialized) return;
997
+ debugMode = options.debug ?? false;
998
+ log("\u{1F680} Initializing Fallom tracing...");
999
+ apiKey = options.apiKey || process.env.FALLOM_API_KEY || null;
1000
+ baseUrl = options.baseUrl || process.env.FALLOM_TRACES_URL || process.env.FALLOM_BASE_URL || "https://traces.fallom.com";
1001
+ const envCapture = process.env.FALLOM_CAPTURE_CONTENT?.toLowerCase();
1002
+ if (envCapture === "false" || envCapture === "0" || envCapture === "no") {
1003
+ captureContent = false;
1004
+ } else {
1005
+ captureContent = options.captureContent ?? true;
1069
1006
  }
1070
- const ctx = sessionStorage.getStore() || fallbackSession;
1071
- const configKey = options.configKey || ctx?.configKey;
1072
- const sessionId = options.sessionId || ctx?.sessionId;
1073
- if (!configKey || !sessionId) {
1007
+ if (!apiKey) {
1074
1008
  throw new Error(
1075
- "No session context. Either call setSession() first, or pass configKey and sessionId explicitly."
1009
+ "No API key provided. Set FALLOM_API_KEY environment variable or pass apiKey parameter."
1076
1010
  );
1077
1011
  }
1078
- sendSpan(configKey, sessionId, data).catch(() => {
1012
+ initialized = true;
1013
+ log("\u{1F4E1} Exporter URL:", `${baseUrl}/v1/traces`);
1014
+ const exporter = new import_exporter_trace_otlp_http.OTLPTraceExporter({
1015
+ url: `${baseUrl}/v1/traces`,
1016
+ headers: {
1017
+ Authorization: `Bearer ${apiKey}`
1018
+ }
1019
+ });
1020
+ const instrumentations = await getInstrumentations();
1021
+ log("\u{1F527} Loaded instrumentations:", instrumentations.length);
1022
+ sdk = new import_sdk_node.NodeSDK({
1023
+ resource: new Resource({
1024
+ "service.name": "fallom-traced-app"
1025
+ }),
1026
+ traceExporter: exporter,
1027
+ spanProcessor: fallomSpanProcessor,
1028
+ instrumentations
1029
+ });
1030
+ sdk.start();
1031
+ log("\u2705 SDK started");
1032
+ process.on("SIGTERM", () => {
1033
+ sdk?.shutdown().catch(console.error);
1079
1034
  });
1080
1035
  }
1081
- async function sendSpan(configKey, sessionId, data) {
1036
+ async function shutdown() {
1037
+ if (sdk) {
1038
+ await sdk.shutdown();
1039
+ initialized = false;
1040
+ }
1041
+ }
1042
+ async function sendTrace(trace) {
1043
+ const url = `${baseUrl}/v1/traces`;
1044
+ log("\u{1F4E4} Sending trace to:", url);
1045
+ log(" Session:", trace.session_id, "Config:", trace.config_key);
1082
1046
  try {
1083
1047
  const controller = new AbortController();
1084
1048
  const timeoutId = setTimeout(() => controller.abort(), 5e3);
1085
- await fetch(`${baseUrl2}/spans`, {
1049
+ const response = await fetch(url, {
1086
1050
  method: "POST",
1087
1051
  headers: {
1088
- Authorization: `Bearer ${apiKey2}`,
1052
+ Authorization: `Bearer ${apiKey}`,
1089
1053
  "Content-Type": "application/json"
1090
1054
  },
1091
- body: JSON.stringify({
1092
- config_key: configKey,
1093
- session_id: sessionId,
1094
- data
1095
- }),
1055
+ body: JSON.stringify(trace),
1096
1056
  signal: controller.signal
1097
1057
  });
1098
1058
  clearTimeout(timeoutId);
1099
- } catch {
1059
+ if (!response.ok) {
1060
+ const text = await response.text();
1061
+ log("\u274C Trace send failed:", response.status, text);
1062
+ } else {
1063
+ log("\u2705 Trace sent:", trace.name, trace.model);
1064
+ }
1065
+ } catch (err) {
1066
+ log("\u274C Trace send error:", err instanceof Error ? err.message : err);
1100
1067
  }
1101
1068
  }
1102
- async function shutdown() {
1103
- if (sdk) {
1104
- await sdk.shutdown();
1105
- initialized2 = false;
1106
- }
1069
+
1070
+ // src/trace/utils.ts
1071
+ function generateHexId(length) {
1072
+ const bytes = new Uint8Array(length / 2);
1073
+ crypto.getRandomValues(bytes);
1074
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
1107
1075
  }
1108
1076
  function messagesToOtelAttributes(messages, completion, model, responseId) {
1109
1077
  const attrs = {};
@@ -1131,65 +1099,28 @@ function messagesToOtelAttributes(messages, completion, model, responseId) {
1131
1099
  }
1132
1100
  return attrs;
1133
1101
  }
1134
- function generateHexId(length) {
1135
- const bytes = new Uint8Array(length / 2);
1136
- crypto.getRandomValues(bytes);
1137
- return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
1138
- }
1139
- var traceContextStorage = new import_async_hooks.AsyncLocalStorage();
1140
- var fallbackTraceContext = null;
1141
- async function sendTrace(trace) {
1142
- const url = `${baseUrl2}/v1/traces`;
1143
- log2("\u{1F4E4} Sending trace to:", url);
1144
- log2(" Session:", trace.session_id, "Config:", trace.config_key);
1145
- try {
1146
- const controller = new AbortController();
1147
- const timeoutId = setTimeout(() => controller.abort(), 5e3);
1148
- const response = await fetch(url, {
1149
- method: "POST",
1150
- headers: {
1151
- Authorization: `Bearer ${apiKey2}`,
1152
- "Content-Type": "application/json"
1153
- },
1154
- body: JSON.stringify(trace),
1155
- signal: controller.signal
1156
- });
1157
- clearTimeout(timeoutId);
1158
- if (!response.ok) {
1159
- const text = await response.text();
1160
- log2("\u274C Trace send failed:", response.status, text);
1161
- } else {
1162
- log2("\u2705 Trace sent:", trace.name, trace.model);
1163
- }
1164
- } catch (err) {
1165
- log2("\u274C Trace send error:", err instanceof Error ? err.message : err);
1166
- }
1167
- }
1168
- function wrapOpenAI(client) {
1102
+
1103
+ // src/trace/wrappers/openai.ts
1104
+ function wrapOpenAI(client, sessionCtx) {
1169
1105
  const originalCreate = client.chat.completions.create.bind(
1170
1106
  client.chat.completions
1171
1107
  );
1108
+ const ctx = sessionCtx;
1172
1109
  client.chat.completions.create = async function(...args) {
1173
- const ctx = sessionStorage.getStore() || fallbackSession;
1174
- if (!ctx || !initialized2) {
1110
+ if (!isInitialized()) {
1175
1111
  return originalCreate(...args);
1176
1112
  }
1177
- let promptCtx = null;
1178
- try {
1179
- const { getPromptContext: getPromptContext2 } = await Promise.resolve().then(() => (init_prompts(), prompts_exports));
1180
- promptCtx = getPromptContext2();
1181
- } catch {
1182
- }
1183
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1113
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1184
1114
  const traceId = traceCtx?.traceId || generateHexId(32);
1185
1115
  const spanId = generateHexId(16);
1186
1116
  const parentSpanId = traceCtx?.parentSpanId;
1187
1117
  const params = args[0] || {};
1188
1118
  const startTime = Date.now();
1119
+ const captureContent2 = shouldCaptureContent();
1189
1120
  try {
1190
1121
  const response = await originalCreate(...args);
1191
1122
  const endTime = Date.now();
1192
- const attributes = captureContent ? messagesToOtelAttributes(
1123
+ const attributes = captureContent2 ? messagesToOtelAttributes(
1193
1124
  params?.messages,
1194
1125
  response?.choices?.[0]?.message,
1195
1126
  response?.model || params?.model,
@@ -1218,17 +1149,13 @@ function wrapOpenAI(client) {
1218
1149
  prompt_tokens: response?.usage?.prompt_tokens,
1219
1150
  completion_tokens: response?.usage?.completion_tokens,
1220
1151
  total_tokens: response?.usage?.total_tokens,
1221
- attributes: Object.keys(attributes).length > 0 ? attributes : void 0,
1222
- prompt_key: promptCtx?.promptKey,
1223
- prompt_version: promptCtx?.promptVersion,
1224
- prompt_ab_test_key: promptCtx?.abTestKey,
1225
- prompt_variant_index: promptCtx?.variantIndex
1152
+ attributes: Object.keys(attributes).length > 0 ? attributes : void 0
1226
1153
  }).catch(() => {
1227
1154
  });
1228
1155
  return response;
1229
1156
  } catch (error) {
1230
1157
  const endTime = Date.now();
1231
- const attributes = captureContent ? messagesToOtelAttributes(
1158
+ const attributes = captureContent2 ? messagesToOtelAttributes(
1232
1159
  params?.messages,
1233
1160
  void 0,
1234
1161
  params?.model,
@@ -1252,11 +1179,7 @@ function wrapOpenAI(client) {
1252
1179
  duration_ms: endTime - startTime,
1253
1180
  status: "ERROR",
1254
1181
  error_message: error?.message,
1255
- attributes,
1256
- prompt_key: promptCtx?.promptKey,
1257
- prompt_version: promptCtx?.promptVersion,
1258
- prompt_ab_test_key: promptCtx?.abTestKey,
1259
- prompt_variant_index: promptCtx?.variantIndex
1182
+ attributes
1260
1183
  }).catch(() => {
1261
1184
  });
1262
1185
  throw error;
@@ -1264,29 +1187,26 @@ function wrapOpenAI(client) {
1264
1187
  };
1265
1188
  return client;
1266
1189
  }
1267
- function wrapAnthropic(client) {
1190
+
1191
+ // src/trace/wrappers/anthropic.ts
1192
+ function wrapAnthropic(client, sessionCtx) {
1268
1193
  const originalCreate = client.messages.create.bind(client.messages);
1194
+ const ctx = sessionCtx;
1269
1195
  client.messages.create = async function(...args) {
1270
- const ctx = sessionStorage.getStore() || fallbackSession;
1271
- if (!ctx || !initialized2) {
1196
+ if (!isInitialized()) {
1272
1197
  return originalCreate(...args);
1273
1198
  }
1274
- let promptCtx = null;
1275
- try {
1276
- const { getPromptContext: getPromptContext2 } = await Promise.resolve().then(() => (init_prompts(), prompts_exports));
1277
- promptCtx = getPromptContext2();
1278
- } catch {
1279
- }
1280
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1199
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1281
1200
  const traceId = traceCtx?.traceId || generateHexId(32);
1282
1201
  const spanId = generateHexId(16);
1283
1202
  const parentSpanId = traceCtx?.parentSpanId;
1284
1203
  const params = args[0] || {};
1285
1204
  const startTime = Date.now();
1205
+ const captureContent2 = shouldCaptureContent();
1286
1206
  try {
1287
1207
  const response = await originalCreate(...args);
1288
1208
  const endTime = Date.now();
1289
- const attributes = captureContent ? messagesToOtelAttributes(
1209
+ const attributes = captureContent2 ? messagesToOtelAttributes(
1290
1210
  params?.messages,
1291
1211
  { role: "assistant", content: response?.content?.[0]?.text || "" },
1292
1212
  response?.model || params?.model,
@@ -1318,17 +1238,13 @@ function wrapAnthropic(client) {
1318
1238
  prompt_tokens: response?.usage?.input_tokens,
1319
1239
  completion_tokens: response?.usage?.output_tokens,
1320
1240
  total_tokens: (response?.usage?.input_tokens || 0) + (response?.usage?.output_tokens || 0),
1321
- attributes: Object.keys(attributes).length > 0 ? attributes : void 0,
1322
- prompt_key: promptCtx?.promptKey,
1323
- prompt_version: promptCtx?.promptVersion,
1324
- prompt_ab_test_key: promptCtx?.abTestKey,
1325
- prompt_variant_index: promptCtx?.variantIndex
1241
+ attributes: Object.keys(attributes).length > 0 ? attributes : void 0
1326
1242
  }).catch(() => {
1327
1243
  });
1328
1244
  return response;
1329
1245
  } catch (error) {
1330
1246
  const endTime = Date.now();
1331
- const attributes = captureContent ? messagesToOtelAttributes(
1247
+ const attributes = captureContent2 ? messagesToOtelAttributes(
1332
1248
  params?.messages,
1333
1249
  void 0,
1334
1250
  params?.model,
@@ -1355,11 +1271,7 @@ function wrapAnthropic(client) {
1355
1271
  duration_ms: endTime - startTime,
1356
1272
  status: "ERROR",
1357
1273
  error_message: error?.message,
1358
- attributes,
1359
- prompt_key: promptCtx?.promptKey,
1360
- prompt_version: promptCtx?.promptVersion,
1361
- prompt_ab_test_key: promptCtx?.abTestKey,
1362
- prompt_variant_index: promptCtx?.variantIndex
1274
+ attributes
1363
1275
  }).catch(() => {
1364
1276
  });
1365
1277
  throw error;
@@ -1367,24 +1279,21 @@ function wrapAnthropic(client) {
1367
1279
  };
1368
1280
  return client;
1369
1281
  }
1370
- function wrapGoogleAI(model) {
1282
+
1283
+ // src/trace/wrappers/google-ai.ts
1284
+ function wrapGoogleAI(model, sessionCtx) {
1371
1285
  const originalGenerate = model.generateContent.bind(model);
1286
+ const ctx = sessionCtx;
1372
1287
  model.generateContent = async function(...args) {
1373
- const ctx = sessionStorage.getStore() || fallbackSession;
1374
- if (!ctx || !initialized2) {
1288
+ if (!isInitialized()) {
1375
1289
  return originalGenerate(...args);
1376
1290
  }
1377
- let promptCtx = null;
1378
- try {
1379
- const { getPromptContext: getPromptContext2 } = await Promise.resolve().then(() => (init_prompts(), prompts_exports));
1380
- promptCtx = getPromptContext2();
1381
- } catch {
1382
- }
1383
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1291
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1384
1292
  const traceId = traceCtx?.traceId || generateHexId(32);
1385
1293
  const spanId = generateHexId(16);
1386
1294
  const parentSpanId = traceCtx?.parentSpanId;
1387
1295
  const startTime = Date.now();
1296
+ const captureContent2 = shouldCaptureContent();
1388
1297
  try {
1389
1298
  const response = await originalGenerate(...args);
1390
1299
  const endTime = Date.now();
@@ -1392,7 +1301,7 @@ function wrapGoogleAI(model) {
1392
1301
  const usage = result?.usageMetadata;
1393
1302
  const modelName = model?.model || "gemini";
1394
1303
  const attributes = {};
1395
- if (captureContent) {
1304
+ if (captureContent2) {
1396
1305
  attributes["gen_ai.request.model"] = modelName;
1397
1306
  attributes["gen_ai.response.model"] = modelName;
1398
1307
  const input = args[0];
@@ -1435,11 +1344,7 @@ function wrapGoogleAI(model) {
1435
1344
  prompt_tokens: usage?.promptTokenCount,
1436
1345
  completion_tokens: usage?.candidatesTokenCount,
1437
1346
  total_tokens: usage?.totalTokenCount,
1438
- attributes: Object.keys(attributes).length > 0 ? attributes : void 0,
1439
- prompt_key: promptCtx?.promptKey,
1440
- prompt_version: promptCtx?.promptVersion,
1441
- prompt_ab_test_key: promptCtx?.abTestKey,
1442
- prompt_variant_index: promptCtx?.variantIndex
1347
+ attributes: Object.keys(attributes).length > 0 ? attributes : void 0
1443
1348
  }).catch(() => {
1444
1349
  });
1445
1350
  return response;
@@ -1447,7 +1352,7 @@ function wrapGoogleAI(model) {
1447
1352
  const endTime = Date.now();
1448
1353
  const modelName = model?.model || "gemini";
1449
1354
  const attributes = {};
1450
- if (captureContent) {
1355
+ if (captureContent2) {
1451
1356
  attributes["gen_ai.request.model"] = modelName;
1452
1357
  attributes["error.message"] = error?.message;
1453
1358
  const input = args[0];
@@ -1471,11 +1376,7 @@ function wrapGoogleAI(model) {
1471
1376
  duration_ms: endTime - startTime,
1472
1377
  status: "ERROR",
1473
1378
  error_message: error?.message,
1474
- attributes: captureContent ? attributes : void 0,
1475
- prompt_key: promptCtx?.promptKey,
1476
- prompt_version: promptCtx?.promptVersion,
1477
- prompt_ab_test_key: promptCtx?.abTestKey,
1478
- prompt_variant_index: promptCtx?.variantIndex
1379
+ attributes: captureContent2 ? attributes : void 0
1479
1380
  }).catch(() => {
1480
1381
  });
1481
1382
  throw error;
@@ -1483,7 +1384,8 @@ function wrapGoogleAI(model) {
1483
1384
  };
1484
1385
  return model;
1485
1386
  }
1486
- var aiSdkDebug = false;
1387
+
1388
+ // src/trace/wrappers/vercel-ai/utils.ts
1487
1389
  function extractUsageFromResult(result, directUsage) {
1488
1390
  let usage = directUsage ?? result?.usage;
1489
1391
  const isValidNumber = (v) => v !== null && v !== void 0 && !Number.isNaN(v);
@@ -1511,38 +1413,25 @@ function extractUsageFromResult(result, directUsage) {
1511
1413
  }
1512
1414
  return { promptTokens, completionTokens, totalTokens, cost };
1513
1415
  }
1514
- function wrapAISDK(ai, options) {
1515
- const aiModule = ai;
1516
- aiSdkDebug = options?.debug ?? false;
1517
- return {
1518
- generateText: createGenerateTextWrapper(aiModule),
1519
- streamText: createStreamTextWrapper(aiModule),
1520
- generateObject: aiModule.generateObject ? createGenerateObjectWrapper(aiModule) : void 0,
1521
- streamObject: aiModule.streamObject ? createStreamObjectWrapper(aiModule) : void 0
1522
- };
1523
- }
1524
- function createGenerateTextWrapper(aiModule) {
1416
+
1417
+ // src/trace/wrappers/vercel-ai/generate-text.ts
1418
+ function createGenerateTextWrapper(aiModule, sessionCtx, debug = false) {
1419
+ const ctx = sessionCtx;
1525
1420
  return async (...args) => {
1526
- const ctx = sessionStorage.getStore() || fallbackSession;
1527
- if (!ctx || !initialized2) {
1421
+ if (!isInitialized()) {
1528
1422
  return aiModule.generateText(...args);
1529
1423
  }
1530
- let promptCtx = null;
1531
- try {
1532
- const { getPromptContext: getPromptContext2 } = await Promise.resolve().then(() => (init_prompts(), prompts_exports));
1533
- promptCtx = getPromptContext2();
1534
- } catch {
1535
- }
1536
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1424
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1537
1425
  const traceId = traceCtx?.traceId || generateHexId(32);
1538
1426
  const spanId = generateHexId(16);
1539
1427
  const parentSpanId = traceCtx?.parentSpanId;
1540
1428
  const params = args[0] || {};
1541
1429
  const startTime = Date.now();
1430
+ const captureContent2 = shouldCaptureContent();
1542
1431
  try {
1543
1432
  const result = await aiModule.generateText(...args);
1544
1433
  const endTime = Date.now();
1545
- if (aiSdkDebug) {
1434
+ if (debug || isDebugMode()) {
1546
1435
  console.log(
1547
1436
  "\n\u{1F50D} [Fallom Debug] generateText result keys:",
1548
1437
  Object.keys(result || {})
@@ -1551,14 +1440,6 @@ function createGenerateTextWrapper(aiModule) {
1551
1440
  "\u{1F50D} [Fallom Debug] result.usage:",
1552
1441
  JSON.stringify(result?.usage, null, 2)
1553
1442
  );
1554
- console.log(
1555
- "\u{1F50D} [Fallom Debug] result.response keys:",
1556
- Object.keys(result?.response || {})
1557
- );
1558
- console.log(
1559
- "\u{1F50D} [Fallom Debug] result.response.usage:",
1560
- JSON.stringify(result?.response?.usage, null, 2)
1561
- );
1562
1443
  console.log(
1563
1444
  "\u{1F50D} [Fallom Debug] result.experimental_providerMetadata:",
1564
1445
  JSON.stringify(result?.experimental_providerMetadata, null, 2)
@@ -1566,7 +1447,7 @@ function createGenerateTextWrapper(aiModule) {
1566
1447
  }
1567
1448
  const modelId = result?.response?.modelId || params?.model?.modelId || String(params?.model || "unknown");
1568
1449
  const attributes = {};
1569
- if (captureContent) {
1450
+ if (captureContent2) {
1570
1451
  attributes["gen_ai.request.model"] = modelId;
1571
1452
  attributes["gen_ai.response.model"] = modelId;
1572
1453
  if (params?.prompt) {
@@ -1616,11 +1497,7 @@ function createGenerateTextWrapper(aiModule) {
1616
1497
  prompt_tokens: usage.promptTokens,
1617
1498
  completion_tokens: usage.completionTokens,
1618
1499
  total_tokens: usage.totalTokens,
1619
- attributes: captureContent ? attributes : void 0,
1620
- prompt_key: promptCtx?.promptKey,
1621
- prompt_version: promptCtx?.promptVersion,
1622
- prompt_ab_test_key: promptCtx?.abTestKey,
1623
- prompt_variant_index: promptCtx?.variantIndex
1500
+ attributes: captureContent2 ? attributes : void 0
1624
1501
  }).catch(() => {
1625
1502
  });
1626
1503
  return result;
@@ -1641,50 +1518,42 @@ function createGenerateTextWrapper(aiModule) {
1641
1518
  end_time: new Date(endTime).toISOString(),
1642
1519
  duration_ms: endTime - startTime,
1643
1520
  status: "ERROR",
1644
- error_message: error?.message,
1645
- prompt_key: promptCtx?.promptKey,
1646
- prompt_version: promptCtx?.promptVersion,
1647
- prompt_ab_test_key: promptCtx?.abTestKey,
1648
- prompt_variant_index: promptCtx?.variantIndex
1521
+ error_message: error?.message
1649
1522
  }).catch(() => {
1650
1523
  });
1651
1524
  throw error;
1652
1525
  }
1653
1526
  };
1654
1527
  }
1655
- function createStreamTextWrapper(aiModule) {
1528
+
1529
+ // src/trace/wrappers/vercel-ai/stream-text.ts
1530
+ function log2(...args) {
1531
+ if (isDebugMode()) console.log("[Fallom]", ...args);
1532
+ }
1533
+ function createStreamTextWrapper(aiModule, sessionCtx, debug = false) {
1534
+ const ctx = sessionCtx;
1656
1535
  return async (...args) => {
1657
- const ctx = sessionStorage.getStore() || fallbackSession;
1658
1536
  const params = args[0] || {};
1659
1537
  const startTime = Date.now();
1538
+ const captureContent2 = shouldCaptureContent();
1660
1539
  const result = await aiModule.streamText(...args);
1661
- if (!ctx || !initialized2) {
1540
+ if (!isInitialized()) {
1662
1541
  return result;
1663
1542
  }
1664
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1543
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1665
1544
  const traceId = traceCtx?.traceId || generateHexId(32);
1666
1545
  const spanId = generateHexId(16);
1667
1546
  const parentSpanId = traceCtx?.parentSpanId;
1668
1547
  let firstTokenTime = null;
1669
1548
  const modelId = params?.model?.modelId || String(params?.model || "unknown");
1670
- let promptCtx = null;
1671
- try {
1672
- const { getPromptContext: getPromptContext2 } = await Promise.resolve().then(() => (init_prompts(), prompts_exports));
1673
- promptCtx = getPromptContext2();
1674
- } catch {
1675
- }
1676
1549
  if (result?.usage) {
1677
1550
  result.usage.then(async (rawUsage) => {
1678
1551
  const endTime = Date.now();
1679
- if (aiSdkDebug) {
1552
+ if (debug || isDebugMode()) {
1680
1553
  console.log(
1681
1554
  "\n\u{1F50D} [Fallom Debug] streamText usage:",
1682
1555
  JSON.stringify(rawUsage, null, 2)
1683
1556
  );
1684
- console.log(
1685
- "\u{1F50D} [Fallom Debug] streamText result keys:",
1686
- Object.keys(result || {})
1687
- );
1688
1557
  }
1689
1558
  log2("\u{1F4CA} streamText usage:", JSON.stringify(rawUsage, null, 2));
1690
1559
  let providerMetadata = result?.experimental_providerMetadata;
@@ -1700,7 +1569,7 @@ function createStreamTextWrapper(aiModule) {
1700
1569
  rawUsage
1701
1570
  );
1702
1571
  const attributes = {};
1703
- if (captureContent) {
1572
+ if (captureContent2) {
1704
1573
  attributes["gen_ai.request.model"] = modelId;
1705
1574
  if (params?.prompt) {
1706
1575
  attributes["gen_ai.prompt.0.role"] = "user";
@@ -1734,11 +1603,7 @@ function createStreamTextWrapper(aiModule) {
1734
1603
  completion_tokens: usage.completionTokens,
1735
1604
  total_tokens: usage.totalTokens,
1736
1605
  time_to_first_token_ms: firstTokenTime ? firstTokenTime - startTime : void 0,
1737
- attributes: captureContent ? attributes : void 0,
1738
- prompt_key: promptCtx?.promptKey,
1739
- prompt_version: promptCtx?.promptVersion,
1740
- prompt_ab_test_key: promptCtx?.abTestKey,
1741
- prompt_variant_index: promptCtx?.variantIndex
1606
+ attributes: captureContent2 ? attributes : void 0
1742
1607
  };
1743
1608
  sendTrace(tracePayload).catch(() => {
1744
1609
  });
@@ -1759,11 +1624,7 @@ function createStreamTextWrapper(aiModule) {
1759
1624
  end_time: new Date(endTime).toISOString(),
1760
1625
  duration_ms: endTime - startTime,
1761
1626
  status: "ERROR",
1762
- error_message: error?.message,
1763
- prompt_key: promptCtx?.promptKey,
1764
- prompt_version: promptCtx?.promptVersion,
1765
- prompt_ab_test_key: promptCtx?.abTestKey,
1766
- prompt_variant_index: promptCtx?.variantIndex
1627
+ error_message: error?.message
1767
1628
  }).catch(() => {
1768
1629
  });
1769
1630
  });
@@ -1791,28 +1652,25 @@ function createStreamTextWrapper(aiModule) {
1791
1652
  return result;
1792
1653
  };
1793
1654
  }
1794
- function createGenerateObjectWrapper(aiModule) {
1655
+
1656
+ // src/trace/wrappers/vercel-ai/generate-object.ts
1657
+ function createGenerateObjectWrapper(aiModule, sessionCtx, debug = false) {
1658
+ const ctx = sessionCtx;
1795
1659
  return async (...args) => {
1796
- const ctx = sessionStorage.getStore() || fallbackSession;
1797
- if (!ctx || !initialized2) {
1660
+ if (!isInitialized()) {
1798
1661
  return aiModule.generateObject(...args);
1799
1662
  }
1800
- let promptCtx = null;
1801
- try {
1802
- const { getPromptContext: getPromptContext2 } = await Promise.resolve().then(() => (init_prompts(), prompts_exports));
1803
- promptCtx = getPromptContext2();
1804
- } catch {
1805
- }
1806
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1663
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1807
1664
  const traceId = traceCtx?.traceId || generateHexId(32);
1808
1665
  const spanId = generateHexId(16);
1809
1666
  const parentSpanId = traceCtx?.parentSpanId;
1810
1667
  const params = args[0] || {};
1811
1668
  const startTime = Date.now();
1669
+ const captureContent2 = shouldCaptureContent();
1812
1670
  try {
1813
1671
  const result = await aiModule.generateObject(...args);
1814
1672
  const endTime = Date.now();
1815
- if (aiSdkDebug) {
1673
+ if (debug || isDebugMode()) {
1816
1674
  console.log(
1817
1675
  "\n\u{1F50D} [Fallom Debug] generateObject result keys:",
1818
1676
  Object.keys(result || {})
@@ -1821,18 +1679,10 @@ function createGenerateObjectWrapper(aiModule) {
1821
1679
  "\u{1F50D} [Fallom Debug] result.usage:",
1822
1680
  JSON.stringify(result?.usage, null, 2)
1823
1681
  );
1824
- console.log(
1825
- "\u{1F50D} [Fallom Debug] result.response keys:",
1826
- Object.keys(result?.response || {})
1827
- );
1828
- console.log(
1829
- "\u{1F50D} [Fallom Debug] result.response.usage:",
1830
- JSON.stringify(result?.response?.usage, null, 2)
1831
- );
1832
1682
  }
1833
1683
  const modelId = result?.response?.modelId || params?.model?.modelId || String(params?.model || "unknown");
1834
1684
  const attributes = {};
1835
- if (captureContent) {
1685
+ if (captureContent2) {
1836
1686
  attributes["gen_ai.request.model"] = modelId;
1837
1687
  attributes["gen_ai.response.model"] = modelId;
1838
1688
  if (result?.object) {
@@ -1871,11 +1721,7 @@ function createGenerateObjectWrapper(aiModule) {
1871
1721
  prompt_tokens: usage.promptTokens,
1872
1722
  completion_tokens: usage.completionTokens,
1873
1723
  total_tokens: usage.totalTokens,
1874
- attributes: captureContent ? attributes : void 0,
1875
- prompt_key: promptCtx?.promptKey,
1876
- prompt_version: promptCtx?.promptVersion,
1877
- prompt_ab_test_key: promptCtx?.abTestKey,
1878
- prompt_variant_index: promptCtx?.variantIndex
1724
+ attributes: captureContent2 ? attributes : void 0
1879
1725
  }).catch(() => {
1880
1726
  });
1881
1727
  return result;
@@ -1896,53 +1742,45 @@ function createGenerateObjectWrapper(aiModule) {
1896
1742
  end_time: new Date(endTime).toISOString(),
1897
1743
  duration_ms: endTime - startTime,
1898
1744
  status: "ERROR",
1899
- error_message: error?.message,
1900
- prompt_key: promptCtx?.promptKey,
1901
- prompt_version: promptCtx?.promptVersion,
1902
- prompt_ab_test_key: promptCtx?.abTestKey,
1903
- prompt_variant_index: promptCtx?.variantIndex
1745
+ error_message: error?.message
1904
1746
  }).catch(() => {
1905
1747
  });
1906
1748
  throw error;
1907
1749
  }
1908
1750
  };
1909
1751
  }
1910
- function createStreamObjectWrapper(aiModule) {
1752
+
1753
+ // src/trace/wrappers/vercel-ai/stream-object.ts
1754
+ function log3(...args) {
1755
+ if (isDebugMode()) console.log("[Fallom]", ...args);
1756
+ }
1757
+ function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
1758
+ const ctx = sessionCtx;
1911
1759
  return async (...args) => {
1912
- const ctx = sessionStorage.getStore() || fallbackSession;
1913
1760
  const params = args[0] || {};
1914
1761
  const startTime = Date.now();
1762
+ const captureContent2 = shouldCaptureContent();
1915
1763
  const result = await aiModule.streamObject(...args);
1916
- log2("\u{1F50D} streamObject result keys:", Object.keys(result || {}));
1917
- if (!ctx || !initialized2) {
1764
+ log3("\u{1F50D} streamObject result keys:", Object.keys(result || {}));
1765
+ if (!isInitialized()) {
1918
1766
  return result;
1919
1767
  }
1920
- const traceCtx = traceContextStorage.getStore() || fallbackTraceContext;
1768
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
1921
1769
  const traceId = traceCtx?.traceId || generateHexId(32);
1922
1770
  const spanId = generateHexId(16);
1923
1771
  const parentSpanId = traceCtx?.parentSpanId;
1924
1772
  let firstTokenTime = null;
1925
1773
  const modelId = params?.model?.modelId || String(params?.model || "unknown");
1926
- let promptCtx = null;
1927
- try {
1928
- const { getPromptContext: getPromptContext2 } = await Promise.resolve().then(() => (init_prompts(), prompts_exports));
1929
- promptCtx = getPromptContext2();
1930
- } catch {
1931
- }
1932
1774
  if (result?.usage) {
1933
1775
  result.usage.then(async (rawUsage) => {
1934
1776
  const endTime = Date.now();
1935
- if (aiSdkDebug) {
1777
+ if (debug || isDebugMode()) {
1936
1778
  console.log(
1937
1779
  "\n\u{1F50D} [Fallom Debug] streamObject usage:",
1938
1780
  JSON.stringify(rawUsage, null, 2)
1939
1781
  );
1940
- console.log(
1941
- "\u{1F50D} [Fallom Debug] streamObject result keys:",
1942
- Object.keys(result || {})
1943
- );
1944
1782
  }
1945
- log2("\u{1F4CA} streamObject usage:", JSON.stringify(rawUsage, null, 2));
1783
+ log3("\u{1F4CA} streamObject usage:", JSON.stringify(rawUsage, null, 2));
1946
1784
  let providerMetadata = result?.experimental_providerMetadata;
1947
1785
  if (providerMetadata && typeof providerMetadata.then === "function") {
1948
1786
  try {
@@ -1956,7 +1794,7 @@ function createStreamObjectWrapper(aiModule) {
1956
1794
  rawUsage
1957
1795
  );
1958
1796
  const attributes = {};
1959
- if (captureContent) {
1797
+ if (captureContent2) {
1960
1798
  attributes["gen_ai.request.model"] = modelId;
1961
1799
  }
1962
1800
  if (firstTokenTime) {
@@ -1985,11 +1823,7 @@ function createStreamObjectWrapper(aiModule) {
1985
1823
  prompt_tokens: usage.promptTokens,
1986
1824
  completion_tokens: usage.completionTokens,
1987
1825
  total_tokens: usage.totalTokens,
1988
- attributes: captureContent ? attributes : void 0,
1989
- prompt_key: promptCtx?.promptKey,
1990
- prompt_version: promptCtx?.promptVersion,
1991
- prompt_ab_test_key: promptCtx?.abTestKey,
1992
- prompt_variant_index: promptCtx?.variantIndex
1826
+ attributes: captureContent2 ? attributes : void 0
1993
1827
  }).catch(() => {
1994
1828
  });
1995
1829
  }).catch((error) => {
@@ -2008,11 +1842,7 @@ function createStreamObjectWrapper(aiModule) {
2008
1842
  end_time: new Date(endTime).toISOString(),
2009
1843
  duration_ms: endTime - startTime,
2010
1844
  status: "ERROR",
2011
- error_message: error?.message,
2012
- prompt_key: promptCtx?.promptKey,
2013
- prompt_version: promptCtx?.promptVersion,
2014
- prompt_ab_test_key: promptCtx?.abTestKey,
2015
- prompt_variant_index: promptCtx?.variantIndex
1845
+ error_message: error?.message
2016
1846
  }).catch(() => {
2017
1847
  });
2018
1848
  });
@@ -2023,7 +1853,7 @@ function createStreamObjectWrapper(aiModule) {
2023
1853
  for await (const chunk of originalStream) {
2024
1854
  if (!firstTokenTime) {
2025
1855
  firstTokenTime = Date.now();
2026
- log2("\u23F1\uFE0F Time to first token:", firstTokenTime - startTime, "ms");
1856
+ log3("\u23F1\uFE0F Time to first token:", firstTokenTime - startTime, "ms");
2027
1857
  }
2028
1858
  yield chunk;
2029
1859
  }
@@ -2040,20 +1870,27 @@ function createStreamObjectWrapper(aiModule) {
2040
1870
  return result;
2041
1871
  };
2042
1872
  }
2043
- function wrapMastraAgent(agent) {
1873
+
1874
+ // src/trace/wrappers/vercel-ai/index.ts
1875
+ function wrapAISDK(ai, sessionCtx, options) {
1876
+ const debug = options?.debug ?? false;
1877
+ return {
1878
+ generateText: createGenerateTextWrapper(ai, sessionCtx, debug),
1879
+ streamText: createStreamTextWrapper(ai, sessionCtx, debug),
1880
+ generateObject: ai.generateObject ? createGenerateObjectWrapper(ai, sessionCtx, debug) : void 0,
1881
+ streamObject: ai.streamObject ? createStreamObjectWrapper(ai, sessionCtx, debug) : void 0
1882
+ };
1883
+ }
1884
+
1885
+ // src/trace/wrappers/mastra.ts
1886
+ function wrapMastraAgent(agent, sessionCtx) {
2044
1887
  const originalGenerate = agent.generate.bind(agent);
2045
1888
  const agentName = agent.name || "MastraAgent";
1889
+ const ctx = sessionCtx;
2046
1890
  agent.generate = async function(...args) {
2047
- const ctx = sessionStorage.getStore() || fallbackSession;
2048
- if (!ctx || !initialized2) {
1891
+ if (!isInitialized()) {
2049
1892
  return originalGenerate(...args);
2050
1893
  }
2051
- let promptCtx = null;
2052
- try {
2053
- const { getPromptContext: getPromptContext2 } = await Promise.resolve().then(() => (init_prompts(), prompts_exports));
2054
- promptCtx = getPromptContext2();
2055
- } catch {
2056
- }
2057
1894
  const traceId = generateHexId(32);
2058
1895
  const spanId = generateHexId(16);
2059
1896
  const startTime = Date.now();
@@ -2125,11 +1962,7 @@ function wrapMastraAgent(agent) {
2125
1962
  prompt_tokens: result?.usage?.promptTokens,
2126
1963
  completion_tokens: result?.usage?.completionTokens,
2127
1964
  total_tokens: result?.usage?.totalTokens,
2128
- attributes,
2129
- prompt_key: promptCtx?.promptKey,
2130
- prompt_version: promptCtx?.promptVersion,
2131
- prompt_ab_test_key: promptCtx?.abTestKey,
2132
- prompt_variant_index: promptCtx?.variantIndex
1965
+ attributes
2133
1966
  };
2134
1967
  sendTrace(traceData).catch(() => {
2135
1968
  });
@@ -2148,11 +1981,7 @@ function wrapMastraAgent(agent) {
2148
1981
  end_time: new Date(endTime).toISOString(),
2149
1982
  duration_ms: endTime - startTime,
2150
1983
  status: "ERROR",
2151
- error_message: error instanceof Error ? error.message : String(error),
2152
- prompt_key: promptCtx?.promptKey,
2153
- prompt_version: promptCtx?.promptVersion,
2154
- prompt_ab_test_key: promptCtx?.abTestKey,
2155
- prompt_variant_index: promptCtx?.variantIndex
1984
+ error_message: error instanceof Error ? error.message : String(error)
2156
1985
  };
2157
1986
  sendTrace(traceData).catch(() => {
2158
1987
  });
@@ -2162,38 +1991,218 @@ function wrapMastraAgent(agent) {
2162
1991
  return agent;
2163
1992
  }
2164
1993
 
2165
- // src/models.ts
2166
- var models_exports = {};
2167
- __export(models_exports, {
1994
+ // src/trace/session.ts
1995
+ var FallomSession = class {
1996
+ constructor(options) {
1997
+ this.ctx = {
1998
+ configKey: options.configKey,
1999
+ sessionId: options.sessionId,
2000
+ customerId: options.customerId
2001
+ };
2002
+ }
2003
+ /** Get the session context. */
2004
+ getContext() {
2005
+ return { ...this.ctx };
2006
+ }
2007
+ /**
2008
+ * Get model assignment for this session (A/B testing).
2009
+ */
2010
+ async getModel(configKeyOrOptions, options) {
2011
+ let configKey;
2012
+ let opts;
2013
+ if (typeof configKeyOrOptions === "string") {
2014
+ configKey = configKeyOrOptions;
2015
+ opts = options || {};
2016
+ } else {
2017
+ configKey = this.ctx.configKey;
2018
+ opts = configKeyOrOptions || {};
2019
+ }
2020
+ const { get: get3 } = await Promise.resolve().then(() => (init_models(), models_exports));
2021
+ return get3(configKey, this.ctx.sessionId, opts);
2022
+ }
2023
+ /**
2024
+ * Wrap a Vercel AI SDK model to trace all calls (PostHog style).
2025
+ * Returns the same model type with tracing injected.
2026
+ */
2027
+ traceModel(model) {
2028
+ const ctx = this.ctx;
2029
+ const tracedModel = Object.create(model);
2030
+ const m = model;
2031
+ if (m.doGenerate) {
2032
+ const originalDoGenerate = m.doGenerate.bind(model);
2033
+ tracedModel.doGenerate = async function(...args) {
2034
+ if (!isInitialized()) return originalDoGenerate(...args);
2035
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
2036
+ const traceId = traceCtx?.traceId || generateHexId(32);
2037
+ const spanId = generateHexId(16);
2038
+ const startTime = Date.now();
2039
+ try {
2040
+ const result = await originalDoGenerate(...args);
2041
+ const endTime = Date.now();
2042
+ const modelId = model.modelId || "unknown";
2043
+ const usage = result?.usage || result?.rawResponse?.usage;
2044
+ sendTrace({
2045
+ config_key: ctx.configKey,
2046
+ session_id: ctx.sessionId,
2047
+ customer_id: ctx.customerId,
2048
+ trace_id: traceId,
2049
+ span_id: spanId,
2050
+ parent_span_id: traceCtx?.parentSpanId,
2051
+ name: "generateText",
2052
+ kind: "llm",
2053
+ model: modelId,
2054
+ start_time: new Date(startTime).toISOString(),
2055
+ end_time: new Date(endTime).toISOString(),
2056
+ duration_ms: endTime - startTime,
2057
+ status: "OK",
2058
+ prompt_tokens: usage?.promptTokens,
2059
+ completion_tokens: usage?.completionTokens,
2060
+ total_tokens: usage?.totalTokens,
2061
+ attributes: shouldCaptureContent() && usage ? { "fallom.raw.usage": JSON.stringify(usage) } : void 0
2062
+ }).catch(() => {
2063
+ });
2064
+ return result;
2065
+ } catch (error) {
2066
+ const endTime = Date.now();
2067
+ sendTrace({
2068
+ config_key: ctx.configKey,
2069
+ session_id: ctx.sessionId,
2070
+ customer_id: ctx.customerId,
2071
+ trace_id: traceId,
2072
+ span_id: spanId,
2073
+ parent_span_id: traceCtx?.parentSpanId,
2074
+ name: "generateText",
2075
+ kind: "llm",
2076
+ model: model.modelId || "unknown",
2077
+ start_time: new Date(startTime).toISOString(),
2078
+ end_time: new Date(endTime).toISOString(),
2079
+ duration_ms: endTime - startTime,
2080
+ status: "ERROR",
2081
+ error_message: error instanceof Error ? error.message : String(error)
2082
+ }).catch(() => {
2083
+ });
2084
+ throw error;
2085
+ }
2086
+ };
2087
+ }
2088
+ if (m.doStream) {
2089
+ const originalDoStream = m.doStream.bind(model);
2090
+ tracedModel.doStream = async function(...args) {
2091
+ if (!isInitialized()) return originalDoStream(...args);
2092
+ const traceCtx = getTraceContextStorage().getStore() || getFallbackTraceContext();
2093
+ const traceId = traceCtx?.traceId || generateHexId(32);
2094
+ const spanId = generateHexId(16);
2095
+ const startTime = Date.now();
2096
+ const modelId = model.modelId || "unknown";
2097
+ try {
2098
+ const result = await originalDoStream(...args);
2099
+ sendTrace({
2100
+ config_key: ctx.configKey,
2101
+ session_id: ctx.sessionId,
2102
+ customer_id: ctx.customerId,
2103
+ trace_id: traceId,
2104
+ span_id: spanId,
2105
+ parent_span_id: traceCtx?.parentSpanId,
2106
+ name: "streamText",
2107
+ kind: "llm",
2108
+ model: modelId,
2109
+ start_time: new Date(startTime).toISOString(),
2110
+ end_time: new Date(Date.now()).toISOString(),
2111
+ duration_ms: Date.now() - startTime,
2112
+ status: "OK",
2113
+ is_streaming: true
2114
+ }).catch(() => {
2115
+ });
2116
+ return result;
2117
+ } catch (error) {
2118
+ sendTrace({
2119
+ config_key: ctx.configKey,
2120
+ session_id: ctx.sessionId,
2121
+ customer_id: ctx.customerId,
2122
+ trace_id: traceId,
2123
+ span_id: spanId,
2124
+ parent_span_id: traceCtx?.parentSpanId,
2125
+ name: "streamText",
2126
+ kind: "llm",
2127
+ model: modelId,
2128
+ start_time: new Date(startTime).toISOString(),
2129
+ end_time: new Date(Date.now()).toISOString(),
2130
+ duration_ms: Date.now() - startTime,
2131
+ status: "ERROR",
2132
+ error_message: error instanceof Error ? error.message : String(error),
2133
+ is_streaming: true
2134
+ }).catch(() => {
2135
+ });
2136
+ throw error;
2137
+ }
2138
+ };
2139
+ }
2140
+ return tracedModel;
2141
+ }
2142
+ /** Wrap OpenAI client. Delegates to shared wrapper. */
2143
+ wrapOpenAI(client) {
2144
+ return wrapOpenAI(client, this.ctx);
2145
+ }
2146
+ /** Wrap Anthropic client. Delegates to shared wrapper. */
2147
+ wrapAnthropic(client) {
2148
+ return wrapAnthropic(client, this.ctx);
2149
+ }
2150
+ /** Wrap Google AI model. Delegates to shared wrapper. */
2151
+ wrapGoogleAI(model) {
2152
+ return wrapGoogleAI(model, this.ctx);
2153
+ }
2154
+ /** Wrap Vercel AI SDK. Delegates to shared wrapper. */
2155
+ wrapAISDK(ai, options) {
2156
+ return wrapAISDK(ai, this.ctx, options);
2157
+ }
2158
+ /** Wrap Mastra agent. Delegates to shared wrapper. */
2159
+ wrapMastraAgent(agent) {
2160
+ return wrapMastraAgent(agent, this.ctx);
2161
+ }
2162
+ };
2163
+ function session(options) {
2164
+ return new FallomSession(options);
2165
+ }
2166
+
2167
+ // src/index.ts
2168
+ init_models();
2169
+
2170
+ // src/prompts.ts
2171
+ var prompts_exports = {};
2172
+ __export(prompts_exports, {
2173
+ clearPromptContext: () => clearPromptContext,
2168
2174
  get: () => get2,
2175
+ getAB: () => getAB,
2176
+ getPromptContext: () => getPromptContext,
2169
2177
  init: () => init3
2170
2178
  });
2171
2179
  var import_crypto2 = require("crypto");
2172
2180
  var apiKey3 = null;
2173
- var baseUrl3 = "https://configs.fallom.com";
2181
+ var baseUrl3 = "https://prompts.fallom.com";
2174
2182
  var initialized3 = false;
2175
2183
  var syncInterval2 = null;
2176
2184
  var debugMode3 = false;
2177
- var configCache = /* @__PURE__ */ new Map();
2185
+ var promptCache = /* @__PURE__ */ new Map();
2186
+ var promptABCache = /* @__PURE__ */ new Map();
2187
+ var promptContext = null;
2178
2188
  var SYNC_TIMEOUT2 = 2e3;
2179
- var RECORD_TIMEOUT = 1e3;
2180
- function log3(msg) {
2189
+ function log5(msg) {
2181
2190
  if (debugMode3) {
2182
- console.log(`[Fallom] ${msg}`);
2191
+ console.log(`[Fallom Prompts] ${msg}`);
2183
2192
  }
2184
2193
  }
2185
2194
  function init3(options = {}) {
2186
2195
  apiKey3 = options.apiKey || process.env.FALLOM_API_KEY || null;
2187
- baseUrl3 = options.baseUrl || process.env.FALLOM_CONFIGS_URL || process.env.FALLOM_BASE_URL || "https://configs.fallom.com";
2196
+ baseUrl3 = options.baseUrl || process.env.FALLOM_PROMPTS_URL || process.env.FALLOM_BASE_URL || "https://prompts.fallom.com";
2188
2197
  initialized3 = true;
2189
2198
  if (!apiKey3) {
2190
2199
  return;
2191
2200
  }
2192
- fetchConfigs().catch(() => {
2201
+ fetchAll().catch(() => {
2193
2202
  });
2194
2203
  if (!syncInterval2) {
2195
2204
  syncInterval2 = setInterval(() => {
2196
- fetchConfigs().catch(() => {
2205
+ fetchAll().catch(() => {
2197
2206
  });
2198
2207
  }, 3e4);
2199
2208
  syncInterval2.unref();
@@ -2207,231 +2216,221 @@ function ensureInit2() {
2207
2216
  }
2208
2217
  }
2209
2218
  }
2210
- async function fetchConfigs(timeout = SYNC_TIMEOUT2) {
2211
- if (!apiKey3) {
2212
- log3("_fetchConfigs: No API key, skipping");
2213
- return;
2219
+ async function fetchAll() {
2220
+ await Promise.all([fetchPrompts(), fetchPromptABTests()]);
2221
+ }
2222
+ async function fetchPrompts(timeout = SYNC_TIMEOUT2) {
2223
+ if (!apiKey3) return;
2224
+ try {
2225
+ const controller = new AbortController();
2226
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
2227
+ const resp = await fetch(`${baseUrl3}/prompts`, {
2228
+ headers: { Authorization: `Bearer ${apiKey3}` },
2229
+ signal: controller.signal
2230
+ });
2231
+ clearTimeout(timeoutId);
2232
+ if (resp.ok) {
2233
+ const data = await resp.json();
2234
+ for (const p of data.prompts || []) {
2235
+ if (!promptCache.has(p.key)) {
2236
+ promptCache.set(p.key, { versions: /* @__PURE__ */ new Map(), current: null });
2237
+ }
2238
+ const cached = promptCache.get(p.key);
2239
+ cached.versions.set(p.version, {
2240
+ systemPrompt: p.system_prompt,
2241
+ userTemplate: p.user_template
2242
+ });
2243
+ cached.current = p.version;
2244
+ }
2245
+ }
2246
+ } catch {
2214
2247
  }
2248
+ }
2249
+ async function fetchPromptABTests(timeout = SYNC_TIMEOUT2) {
2250
+ if (!apiKey3) return;
2215
2251
  try {
2216
- log3(`Fetching configs from ${baseUrl3}/configs`);
2217
2252
  const controller = new AbortController();
2218
2253
  const timeoutId = setTimeout(() => controller.abort(), timeout);
2219
- const resp = await fetch(`${baseUrl3}/configs`, {
2254
+ const resp = await fetch(`${baseUrl3}/prompt-ab-tests`, {
2220
2255
  headers: { Authorization: `Bearer ${apiKey3}` },
2221
2256
  signal: controller.signal
2222
2257
  });
2223
2258
  clearTimeout(timeoutId);
2224
- log3(`Response status: ${resp.status}`);
2225
2259
  if (resp.ok) {
2226
2260
  const data = await resp.json();
2227
- const configs = data.configs || [];
2228
- log3(`Got ${configs.length} configs: ${configs.map((c) => c.key)}`);
2229
- for (const c of configs) {
2230
- const key = c.key;
2231
- const version = c.version || 1;
2232
- log3(`Config '${key}' v${version}: ${JSON.stringify(c.variants)}`);
2233
- if (!configCache.has(key)) {
2234
- configCache.set(key, { versions: /* @__PURE__ */ new Map(), latest: null });
2261
+ for (const t of data.prompt_ab_tests || []) {
2262
+ if (!promptABCache.has(t.key)) {
2263
+ promptABCache.set(t.key, { versions: /* @__PURE__ */ new Map(), current: null });
2235
2264
  }
2236
- const cached = configCache.get(key);
2237
- cached.versions.set(version, c);
2238
- cached.latest = version;
2265
+ const cached = promptABCache.get(t.key);
2266
+ cached.versions.set(t.version, { variants: t.variants });
2267
+ cached.current = t.version;
2239
2268
  }
2240
- } else {
2241
- log3(`Fetch failed: ${resp.statusText}`);
2242
2269
  }
2243
- } catch (e) {
2244
- log3(`Fetch exception: ${e}`);
2270
+ } catch {
2245
2271
  }
2246
2272
  }
2247
- async function fetchSpecificVersion(configKey, version, timeout = SYNC_TIMEOUT2) {
2248
- if (!apiKey3) return null;
2249
- try {
2250
- const controller = new AbortController();
2251
- const timeoutId = setTimeout(() => controller.abort(), timeout);
2252
- const resp = await fetch(
2253
- `${baseUrl3}/configs/${configKey}/version/${version}`,
2254
- {
2255
- headers: { Authorization: `Bearer ${apiKey3}` },
2256
- signal: controller.signal
2257
- }
2273
+ function replaceVariables(template, variables) {
2274
+ if (!variables) return template;
2275
+ return template.replace(/\{\{(\s*\w+\s*)\}\}/g, (match, varName) => {
2276
+ const key = varName.trim();
2277
+ return key in variables ? String(variables[key]) : match;
2278
+ });
2279
+ }
2280
+ function setPromptContext(ctx) {
2281
+ promptContext = ctx;
2282
+ }
2283
+ function getPromptContext() {
2284
+ const ctx = promptContext;
2285
+ promptContext = null;
2286
+ return ctx;
2287
+ }
2288
+ async function get2(promptKey, options = {}) {
2289
+ const { variables, version, debug = false } = options;
2290
+ debugMode3 = debug;
2291
+ ensureInit2();
2292
+ log5(`get() called: promptKey=${promptKey}`);
2293
+ let promptData = promptCache.get(promptKey);
2294
+ if (!promptData) {
2295
+ log5("Not in cache, fetching...");
2296
+ await fetchPrompts(SYNC_TIMEOUT2);
2297
+ promptData = promptCache.get(promptKey);
2298
+ }
2299
+ if (!promptData) {
2300
+ throw new Error(
2301
+ `Prompt '${promptKey}' not found. Check that it exists in your Fallom dashboard.`
2258
2302
  );
2259
- clearTimeout(timeoutId);
2260
- if (resp.ok) {
2261
- const config = await resp.json();
2262
- if (!configCache.has(configKey)) {
2263
- configCache.set(configKey, { versions: /* @__PURE__ */ new Map(), latest: null });
2264
- }
2265
- configCache.get(configKey).versions.set(version, config);
2266
- return config;
2267
- }
2268
- } catch {
2269
2303
  }
2270
- return null;
2304
+ const targetVersion = version ?? promptData.current;
2305
+ const content = promptData.versions.get(targetVersion);
2306
+ if (!content) {
2307
+ throw new Error(
2308
+ `Prompt '${promptKey}' version ${targetVersion} not found.`
2309
+ );
2310
+ }
2311
+ const system = replaceVariables(content.systemPrompt, variables);
2312
+ const user = replaceVariables(content.userTemplate, variables);
2313
+ setPromptContext({
2314
+ promptKey,
2315
+ promptVersion: targetVersion
2316
+ });
2317
+ log5(`\u2705 Got prompt: ${promptKey} v${targetVersion}`);
2318
+ return {
2319
+ key: promptKey,
2320
+ version: targetVersion,
2321
+ system,
2322
+ user
2323
+ };
2271
2324
  }
2272
- async function get2(configKey, sessionId, options = {}) {
2273
- const { version, fallback, debug = false } = options;
2325
+ async function getAB(abTestKey, sessionId, options = {}) {
2326
+ const { variables, debug = false } = options;
2274
2327
  debugMode3 = debug;
2275
2328
  ensureInit2();
2276
- log3(
2277
- `get() called: configKey=${configKey}, sessionId=${sessionId}, fallback=${fallback}`
2278
- );
2279
- try {
2280
- let configData = configCache.get(configKey);
2281
- log3(
2282
- `Cache lookup for '${configKey}': ${configData ? "found" : "not found"}`
2329
+ log5(`getAB() called: abTestKey=${abTestKey}, sessionId=${sessionId}`);
2330
+ let abData = promptABCache.get(abTestKey);
2331
+ if (!abData) {
2332
+ log5("Not in cache, fetching...");
2333
+ await fetchPromptABTests(SYNC_TIMEOUT2);
2334
+ abData = promptABCache.get(abTestKey);
2335
+ }
2336
+ if (!abData) {
2337
+ throw new Error(
2338
+ `Prompt A/B test '${abTestKey}' not found. Check that it exists in your Fallom dashboard.`
2283
2339
  );
2284
- if (!configData) {
2285
- log3("Not in cache, fetching...");
2286
- await fetchConfigs(SYNC_TIMEOUT2);
2287
- configData = configCache.get(configKey);
2288
- log3(
2289
- `After fetch, cache lookup: ${configData ? "found" : "still not found"}`
2290
- );
2291
- }
2292
- if (!configData) {
2293
- log3(`Config not found, using fallback: ${fallback}`);
2294
- if (fallback) {
2295
- console.warn(
2296
- `[Fallom WARNING] Config '${configKey}' not found, using fallback model: ${fallback}`
2297
- );
2298
- return returnWithTrace(configKey, sessionId, fallback, 0);
2299
- }
2300
- throw new Error(
2301
- `Config '${configKey}' not found. Check that it exists in your Fallom dashboard.`
2302
- );
2303
- }
2304
- let config;
2305
- let targetVersion;
2306
- if (version !== void 0) {
2307
- config = configData.versions.get(version);
2308
- if (!config) {
2309
- config = await fetchSpecificVersion(configKey, version, SYNC_TIMEOUT2) || void 0;
2310
- }
2311
- if (!config) {
2312
- if (fallback) {
2313
- console.warn(
2314
- `[Fallom WARNING] Config '${configKey}' version ${version} not found, using fallback: ${fallback}`
2315
- );
2316
- return returnWithTrace(configKey, sessionId, fallback, 0);
2317
- }
2318
- throw new Error(`Config '${configKey}' version ${version} not found.`);
2319
- }
2320
- targetVersion = version;
2321
- } else {
2322
- targetVersion = configData.latest;
2323
- config = configData.versions.get(targetVersion);
2324
- if (!config) {
2325
- if (fallback) {
2326
- console.warn(
2327
- `[Fallom WARNING] Config '${configKey}' has no cached version, using fallback: ${fallback}`
2328
- );
2329
- return returnWithTrace(configKey, sessionId, fallback, 0);
2330
- }
2331
- throw new Error(`Config '${configKey}' has no cached version.`);
2332
- }
2333
- }
2334
- const variantsRaw = config.variants;
2335
- const configVersion = config.version || targetVersion;
2336
- const variants = Array.isArray(variantsRaw) ? variantsRaw : Object.values(variantsRaw);
2337
- log3(
2338
- `Config found! Version: ${configVersion}, Variants: ${JSON.stringify(
2339
- variants
2340
- )}`
2340
+ }
2341
+ const currentVersion = abData.current;
2342
+ const versionData = abData.versions.get(currentVersion);
2343
+ if (!versionData) {
2344
+ throw new Error(`Prompt A/B test '${abTestKey}' has no current version.`);
2345
+ }
2346
+ const { variants } = versionData;
2347
+ log5(`A/B test '${abTestKey}' has ${variants?.length ?? 0} variants`);
2348
+ log5(`Version data: ${JSON.stringify(versionData, null, 2)}`);
2349
+ if (!variants || variants.length === 0) {
2350
+ throw new Error(
2351
+ `Prompt A/B test '${abTestKey}' has no variants configured.`
2341
2352
  );
2342
- const hashBytes = (0, import_crypto2.createHash)("md5").update(sessionId).digest();
2343
- const hashVal = hashBytes.readUInt32BE(0) % 1e6;
2344
- log3(`Session hash: ${hashVal} (out of 1,000,000)`);
2345
- let cumulative = 0;
2346
- let assignedModel = variants[variants.length - 1].model;
2347
- for (const v of variants) {
2348
- const oldCumulative = cumulative;
2349
- cumulative += v.weight * 1e4;
2350
- log3(
2351
- `Variant ${v.model}: weight=${v.weight}%, range=${oldCumulative}-${cumulative}, hash=${hashVal}, match=${hashVal < cumulative}`
2352
- );
2353
- if (hashVal < cumulative) {
2354
- assignedModel = v.model;
2355
- break;
2356
- }
2357
- }
2358
- log3(`\u2705 Assigned model: ${assignedModel}`);
2359
- return returnWithTrace(configKey, sessionId, assignedModel, configVersion);
2360
- } catch (e) {
2361
- if (e instanceof Error && e.message.includes("not found")) {
2362
- throw e;
2363
- }
2364
- if (fallback) {
2365
- console.warn(
2366
- `[Fallom WARNING] Error getting model for '${configKey}': ${e}. Using fallback: ${fallback}`
2367
- );
2368
- return returnWithTrace(configKey, sessionId, fallback, 0);
2353
+ }
2354
+ const hashBytes = (0, import_crypto2.createHash)("md5").update(sessionId).digest();
2355
+ const hashVal = hashBytes.readUInt32BE(0) % 1e6;
2356
+ let cumulative = 0;
2357
+ let selectedVariant = variants[variants.length - 1];
2358
+ let selectedIndex = variants.length - 1;
2359
+ for (let i = 0; i < variants.length; i++) {
2360
+ cumulative += variants[i].weight * 1e4;
2361
+ if (hashVal < cumulative) {
2362
+ selectedVariant = variants[i];
2363
+ selectedIndex = i;
2364
+ break;
2369
2365
  }
2370
- throw e;
2371
2366
  }
2372
- }
2373
- function returnWithTrace(configKey, sessionId, model, version) {
2374
- try {
2375
- setSession(configKey, sessionId);
2376
- } catch {
2367
+ const promptKey = selectedVariant.prompt_key;
2368
+ const promptVersion = selectedVariant.prompt_version;
2369
+ let promptData = promptCache.get(promptKey);
2370
+ if (!promptData) {
2371
+ await fetchPrompts(SYNC_TIMEOUT2);
2372
+ promptData = promptCache.get(promptKey);
2377
2373
  }
2378
- if (version > 0) {
2379
- recordSession(configKey, version, sessionId, model).catch(() => {
2380
- });
2374
+ if (!promptData) {
2375
+ throw new Error(
2376
+ `Prompt '${promptKey}' (from A/B test '${abTestKey}') not found.`
2377
+ );
2381
2378
  }
2382
- return model;
2383
- }
2384
- async function recordSession(configKey, version, sessionId, model) {
2385
- if (!apiKey3) return;
2386
- try {
2387
- const controller = new AbortController();
2388
- const timeoutId = setTimeout(() => controller.abort(), RECORD_TIMEOUT);
2389
- await fetch(`${baseUrl3}/sessions`, {
2390
- method: "POST",
2391
- headers: {
2392
- Authorization: `Bearer ${apiKey3}`,
2393
- "Content-Type": "application/json"
2394
- },
2395
- body: JSON.stringify({
2396
- config_key: configKey,
2397
- config_version: version,
2398
- session_id: sessionId,
2399
- assigned_model: model
2400
- }),
2401
- signal: controller.signal
2402
- });
2403
- clearTimeout(timeoutId);
2404
- } catch {
2379
+ const targetVersion = promptVersion ?? promptData.current;
2380
+ const content = promptData.versions.get(targetVersion);
2381
+ if (!content) {
2382
+ throw new Error(
2383
+ `Prompt '${promptKey}' version ${targetVersion} not found.`
2384
+ );
2405
2385
  }
2386
+ const system = replaceVariables(content.systemPrompt, variables);
2387
+ const user = replaceVariables(content.userTemplate, variables);
2388
+ setPromptContext({
2389
+ promptKey,
2390
+ promptVersion: targetVersion,
2391
+ abTestKey,
2392
+ variantIndex: selectedIndex
2393
+ });
2394
+ log5(
2395
+ `\u2705 Got prompt from A/B: ${promptKey} v${targetVersion} (variant ${selectedIndex})`
2396
+ );
2397
+ return {
2398
+ key: promptKey,
2399
+ version: targetVersion,
2400
+ system,
2401
+ user,
2402
+ abTestKey,
2403
+ variantIndex: selectedIndex
2404
+ };
2405
+ }
2406
+ function clearPromptContext() {
2407
+ promptContext = null;
2406
2408
  }
2407
-
2408
- // src/index.ts
2409
- init_prompts();
2410
2409
 
2411
2410
  // src/init.ts
2412
- init_prompts();
2411
+ init_models();
2413
2412
  async function init4(options = {}) {
2414
2413
  const tracesUrl = options.tracesUrl || process.env.FALLOM_TRACES_URL || "https://traces.fallom.com";
2415
2414
  const configsUrl = options.configsUrl || process.env.FALLOM_CONFIGS_URL || "https://configs.fallom.com";
2416
2415
  const promptsUrl = options.promptsUrl || process.env.FALLOM_PROMPTS_URL || "https://prompts.fallom.com";
2417
- await init2({
2416
+ await init({
2418
2417
  apiKey: options.apiKey,
2419
2418
  baseUrl: tracesUrl,
2420
2419
  captureContent: options.captureContent,
2421
2420
  debug: options.debug
2422
2421
  });
2423
- init3({
2422
+ init2({
2424
2423
  apiKey: options.apiKey,
2425
2424
  baseUrl: configsUrl
2426
2425
  });
2427
- init({
2426
+ init3({
2428
2427
  apiKey: options.apiKey,
2429
2428
  baseUrl: promptsUrl
2430
2429
  });
2431
2430
  }
2432
2431
 
2433
2432
  // src/mastra.ts
2434
- var import_core2 = require("@opentelemetry/core");
2433
+ var import_core12 = require("@opentelemetry/core");
2435
2434
  var promptContext2 = {};
2436
2435
  function setMastraPrompt(promptKey, version) {
2437
2436
  promptContext2 = {
@@ -2458,9 +2457,13 @@ var FallomExporter = class {
2458
2457
  this.apiKey = options.apiKey ?? process.env.FALLOM_API_KEY ?? "";
2459
2458
  this.baseUrl = options.baseUrl ?? "https://traces.fallom.com";
2460
2459
  this.debug = options.debug ?? false;
2461
- console.log("[FallomExporter] Constructor called, debug:", this.debug);
2462
- console.log("[FallomExporter] API key present:", !!this.apiKey);
2463
- console.log("[FallomExporter] Base URL:", this.baseUrl);
2460
+ this.session = options.session;
2461
+ if (this.debug) {
2462
+ console.log("[FallomExporter] Constructor called");
2463
+ console.log("[FallomExporter] API key present:", !!this.apiKey);
2464
+ console.log("[FallomExporter] Base URL:", this.baseUrl);
2465
+ console.log("[FallomExporter] Session:", this.session);
2466
+ }
2464
2467
  if (!this.apiKey) {
2465
2468
  console.warn(
2466
2469
  "[FallomExporter] No API key provided. Set FALLOM_API_KEY env var or pass apiKey option."
@@ -2477,15 +2480,15 @@ var FallomExporter = class {
2477
2480
  */
2478
2481
  export(spans, resultCallback) {
2479
2482
  if (spans.length === 0) {
2480
- resultCallback({ code: import_core2.ExportResultCode.SUCCESS });
2483
+ resultCallback({ code: import_core12.ExportResultCode.SUCCESS });
2481
2484
  return;
2482
2485
  }
2483
2486
  this.log(`Exporting ${spans.length} spans...`);
2484
2487
  if (this.debug) {
2485
- for (const span2 of spans) {
2486
- this.log(` - ${span2.name}`, {
2488
+ for (const span of spans) {
2489
+ this.log(` - ${span.name}`, {
2487
2490
  attributes: Object.fromEntries(
2488
- Object.entries(span2.attributes).filter(
2491
+ Object.entries(span.attributes).filter(
2489
2492
  ([k]) => k.startsWith("gen_ai") || k.startsWith("llm")
2490
2493
  )
2491
2494
  )
@@ -2494,11 +2497,11 @@ var FallomExporter = class {
2494
2497
  }
2495
2498
  const exportPromise = this.sendSpans(spans).then(() => {
2496
2499
  this.log("Export successful");
2497
- resultCallback({ code: import_core2.ExportResultCode.SUCCESS });
2500
+ resultCallback({ code: import_core12.ExportResultCode.SUCCESS });
2498
2501
  }).catch((error) => {
2499
2502
  console.error("[FallomExporter] Export failed:", error);
2500
2503
  resultCallback({
2501
- code: import_core2.ExportResultCode.FAILED,
2504
+ code: import_core12.ExportResultCode.FAILED,
2502
2505
  error: error instanceof Error ? error : new Error(String(error))
2503
2506
  });
2504
2507
  });
@@ -2521,20 +2524,19 @@ var FallomExporter = class {
2521
2524
  * Send spans to Fallom's OTLP endpoint.
2522
2525
  */
2523
2526
  async sendSpans(spans) {
2524
- const session = getSession();
2525
2527
  const resourceSpans = this.spansToOtlpJson(spans);
2526
2528
  const headers = {
2527
2529
  "Content-Type": "application/json",
2528
2530
  Authorization: `Bearer ${this.apiKey}`
2529
2531
  };
2530
- if (session?.configKey) {
2531
- headers["X-Fallom-Config-Key"] = session.configKey;
2532
+ if (this.session?.configKey) {
2533
+ headers["X-Fallom-Config-Key"] = this.session.configKey;
2532
2534
  }
2533
- if (session?.sessionId) {
2534
- headers["X-Fallom-Session-Id"] = session.sessionId;
2535
+ if (this.session?.sessionId) {
2536
+ headers["X-Fallom-Session-Id"] = this.session.sessionId;
2535
2537
  }
2536
- if (session?.customerId) {
2537
- headers["X-Fallom-Customer-Id"] = session.customerId;
2538
+ if (this.session?.customerId) {
2539
+ headers["X-Fallom-Customer-Id"] = this.session.customerId;
2538
2540
  }
2539
2541
  if (promptContext2.promptKey) {
2540
2542
  headers["X-Fallom-Prompt-Key"] = promptContext2.promptKey;
@@ -2571,12 +2573,12 @@ var FallomExporter = class {
2571
2573
  */
2572
2574
  spansToOtlpJson(spans) {
2573
2575
  const resourceMap = /* @__PURE__ */ new Map();
2574
- for (const span2 of spans) {
2575
- const resourceKey = JSON.stringify(span2.resource.attributes);
2576
+ for (const span of spans) {
2577
+ const resourceKey = JSON.stringify(span.resource.attributes);
2576
2578
  if (!resourceMap.has(resourceKey)) {
2577
2579
  resourceMap.set(resourceKey, []);
2578
2580
  }
2579
- resourceMap.get(resourceKey).push(span2);
2581
+ resourceMap.get(resourceKey).push(span);
2580
2582
  }
2581
2583
  const resourceSpans = [];
2582
2584
  for (const [_resourceKey, resourceSpanList] of resourceMap) {
@@ -2591,7 +2593,7 @@ var FallomExporter = class {
2591
2593
  name: firstSpan.instrumentationLibrary.name,
2592
2594
  version: firstSpan.instrumentationLibrary.version
2593
2595
  },
2594
- spans: resourceSpanList.map((span2) => this.spanToOtlp(span2))
2596
+ spans: resourceSpanList.map((span) => this.spanToOtlp(span))
2595
2597
  }
2596
2598
  ]
2597
2599
  });
@@ -2601,21 +2603,21 @@ var FallomExporter = class {
2601
2603
  /**
2602
2604
  * Convert a single span to OTLP format.
2603
2605
  */
2604
- spanToOtlp(span2) {
2606
+ spanToOtlp(span) {
2605
2607
  return {
2606
- traceId: span2.spanContext().traceId,
2607
- spanId: span2.spanContext().spanId,
2608
- parentSpanId: span2.parentSpanId,
2609
- name: span2.name,
2610
- kind: span2.kind,
2611
- startTimeUnixNano: this.hrTimeToNanos(span2.startTime),
2612
- endTimeUnixNano: this.hrTimeToNanos(span2.endTime),
2613
- attributes: this.attributesToOtlp(span2.attributes),
2608
+ traceId: span.spanContext().traceId,
2609
+ spanId: span.spanContext().spanId,
2610
+ parentSpanId: span.parentSpanId,
2611
+ name: span.name,
2612
+ kind: span.kind,
2613
+ startTimeUnixNano: this.hrTimeToNanos(span.startTime),
2614
+ endTimeUnixNano: this.hrTimeToNanos(span.endTime),
2615
+ attributes: this.attributesToOtlp(span.attributes),
2614
2616
  status: {
2615
- code: span2.status.code,
2616
- message: span2.status.message
2617
+ code: span.status.code,
2618
+ message: span.status.message
2617
2619
  },
2618
- events: span2.events.map((event) => ({
2620
+ events: span.events.map((event) => ({
2619
2621
  timeUnixNano: this.hrTimeToNanos(event.time),
2620
2622
  name: event.name,
2621
2623
  attributes: this.attributesToOtlp(event.attributes || {})
@@ -2666,20 +2668,23 @@ var FallomExporter = class {
2666
2668
  };
2667
2669
 
2668
2670
  // src/index.ts
2669
- init_prompts();
2671
+ init_models();
2670
2672
  var index_default = {
2671
2673
  init: init4,
2672
2674
  trace: trace_exports,
2673
2675
  models: models_exports,
2674
- prompts: prompts_exports
2676
+ prompts: prompts_exports,
2677
+ session
2675
2678
  };
2676
2679
  // Annotate the CommonJS export names for ESM import in node:
2677
2680
  0 && (module.exports = {
2678
2681
  FallomExporter,
2682
+ FallomSession,
2679
2683
  clearMastraPrompt,
2680
2684
  init,
2681
2685
  models,
2682
2686
  prompts,
2687
+ session,
2683
2688
  setMastraPrompt,
2684
2689
  setMastraPromptAB,
2685
2690
  trace