@mastra/langfuse 0.0.0-toolOptionTypes-20250917085558 → 0.0.0-top-level-fix-20251211111608

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.
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Langfuse Tracing Options Helpers
3
+ *
4
+ * These helpers integrate with the `buildTracingOptions` pattern from
5
+ * `@mastra/observability` to add Langfuse-specific tracing features.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { buildTracingOptions } from '@mastra/observability';
10
+ * import { withLangfusePrompt } from '@mastra/langfuse';
11
+ *
12
+ * const prompt = await langfuse.getPrompt('my-prompt');
13
+ *
14
+ * const agent = new Agent({
15
+ * defaultGenerateOptions: {
16
+ * tracingOptions: buildTracingOptions(withLangfusePrompt(prompt)),
17
+ * },
18
+ * });
19
+ * ```
20
+ */
21
+ import type { TracingOptionsUpdater } from '@mastra/observability';
22
+ /**
23
+ * Langfuse prompt input - accepts either a Langfuse SDK prompt object
24
+ * or manual fields.
25
+ */
26
+ export interface LangfusePromptInput {
27
+ /** Prompt name */
28
+ name?: string;
29
+ /** Prompt version */
30
+ version?: number;
31
+ /** Prompt UUID */
32
+ id?: string;
33
+ }
34
+ /**
35
+ * Adds Langfuse prompt metadata to the tracing options
36
+ * to enable Langfuse Prompt Tracing.
37
+ *
38
+ * The metadata is added under `metadata.langfuse.prompt` and includes:
39
+ * - `name` - Prompt name
40
+ * - `version` - Prompt version
41
+ * - `id` - Prompt UUID
42
+ *
43
+ * All fields are deeply merged with any existing metadata.
44
+ *
45
+ * @param prompt - A Langfuse prompt object (from `langfuse.getPrompt()`) or manual fields
46
+ * @returns A TracingOptionsUpdater function for use with `buildTracingOptions`
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * import { buildTracingOptions } from '@mastra/observability';
51
+ * import { withLangfusePrompt } from '@mastra/langfuse';
52
+ * import { Langfuse } from 'langfuse';
53
+ *
54
+ * const langfuse = new Langfuse();
55
+ * const prompt = await langfuse.getPrompt('customer-support');
56
+ *
57
+ * // Use with buildTracingOptions
58
+ * const tracingOptions = buildTracingOptions(
59
+ * withLangfusePrompt(prompt),
60
+ * );
61
+ *
62
+ * // Or directly in agent config
63
+ * const agent = new Agent({
64
+ * name: 'support-agent',
65
+ * instructions: prompt.prompt,
66
+ * model: openai('gpt-4o'),
67
+ * defaultGenerateOptions: {
68
+ * tracingOptions: buildTracingOptions(withLangfusePrompt(prompt)),
69
+ * },
70
+ * });
71
+ *
72
+ * // Manual fields also work
73
+ * const tracingOptions = buildTracingOptions(
74
+ * withLangfusePrompt({ name: 'my-prompt', version: 1 }),
75
+ * );
76
+ * ```
77
+ */
78
+ export declare function withLangfusePrompt(prompt: LangfusePromptInput): TracingOptionsUpdater;
79
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEnE;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,kBAAkB;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,qBAAqB,CAerF"}
package/dist/index.cjs CHANGED
@@ -1,24 +1,50 @@
1
1
  'use strict';
2
2
 
3
- var aiTracing = require('@mastra/core/ai-tracing');
4
- var logger = require('@mastra/core/logger');
3
+ var observability$1 = require('@mastra/core/observability');
4
+ var utils = require('@mastra/core/utils');
5
+ var observability = require('@mastra/observability');
5
6
  var langfuse = require('langfuse');
6
7
 
7
- // src/ai-tracing.ts
8
- var LangfuseExporter = class {
8
+ // src/tracing.ts
9
+ function formatUsageMetrics(usage) {
10
+ if (!usage) return {};
11
+ const metrics = {};
12
+ if (usage.inputTokens !== void 0) {
13
+ metrics.input = usage.inputTokens;
14
+ if (usage.inputDetails?.cacheWrite !== void 0) {
15
+ metrics.cache_write_input_tokens = usage.inputDetails.cacheWrite;
16
+ metrics.input -= metrics.cache_write_input_tokens;
17
+ }
18
+ }
19
+ if (usage.inputDetails?.cacheRead !== void 0) {
20
+ metrics.cache_read_input_tokens = usage.inputDetails.cacheRead;
21
+ }
22
+ if (usage.outputTokens !== void 0) {
23
+ metrics.output = usage.outputTokens;
24
+ }
25
+ if (usage.outputDetails?.reasoning !== void 0) {
26
+ metrics.reasoning = usage.outputDetails.reasoning;
27
+ }
28
+ if (metrics.input && metrics.output) {
29
+ metrics.total = metrics.input + metrics.output;
30
+ if (metrics.cache_write_input_tokens) {
31
+ metrics.total += metrics.cache_write_input_tokens;
32
+ }
33
+ }
34
+ return metrics;
35
+ }
36
+ var LangfuseExporter = class extends observability.BaseExporter {
9
37
  name = "langfuse";
10
38
  client;
11
39
  realtime;
12
40
  traceMap = /* @__PURE__ */ new Map();
13
- logger;
14
41
  constructor(config) {
42
+ super(config);
15
43
  this.realtime = config.realtime ?? false;
16
- this.logger = new logger.ConsoleLogger({ level: config.logLevel ?? "warn" });
17
44
  if (!config.publicKey || !config.secretKey) {
18
- this.logger.error("LangfuseExporter: Missing required credentials, exporter will be disabled", {
19
- hasPublicKey: !!config.publicKey,
20
- hasSecretKey: !!config.secretKey
21
- });
45
+ this.setDisabled(
46
+ `Missing required credentials (publicKey: ${!!config.publicKey}, secretKey: ${!!config.secretKey})`
47
+ );
22
48
  this.client = null;
23
49
  return;
24
50
  }
@@ -29,10 +55,7 @@ var LangfuseExporter = class {
29
55
  ...config.options
30
56
  });
31
57
  }
32
- async exportEvent(event) {
33
- if (!this.client) {
34
- return;
35
- }
58
+ async _exportTracingEvent(event) {
36
59
  if (event.exportedSpan.isEvent) {
37
60
  await this.handleEventSpan(event.exportedSpan);
38
61
  return;
@@ -61,13 +84,21 @@ var LangfuseExporter = class {
61
84
  if (!traceData) {
62
85
  return;
63
86
  }
87
+ if (!span.isRootSpan) {
88
+ const langfuseData = span.metadata?.langfuse;
89
+ traceData.spanMetadata.set(span.id, {
90
+ parentSpanId: span.parentSpanId,
91
+ langfusePrompt: langfuseData?.prompt
92
+ });
93
+ }
64
94
  const langfuseParent = this.getLangfuseParent({ traceData, span, method });
65
95
  if (!langfuseParent) {
66
96
  return;
67
97
  }
68
- const payload = this.buildSpanPayload(span, true);
69
- const langfuseSpan = span.type === aiTracing.AISpanType.LLM_GENERATION ? langfuseParent.generation(payload) : langfuseParent.span(payload);
98
+ const payload = this.buildSpanPayload(span, true, traceData);
99
+ const langfuseSpan = span.type === observability$1.SpanType.MODEL_GENERATION ? langfuseParent.generation(payload) : langfuseParent.span(payload);
70
100
  traceData.spans.set(span.id, langfuseSpan);
101
+ traceData.activeSpans.add(span.id);
71
102
  }
72
103
  async handleSpanUpdateOrEnd(span, isEnd) {
73
104
  const method = isEnd ? "handleSpanEnd" : "handleSpanUpdate";
@@ -77,6 +108,13 @@ var LangfuseExporter = class {
77
108
  }
78
109
  const langfuseSpan = traceData.spans.get(span.id);
79
110
  if (!langfuseSpan) {
111
+ if (isEnd && span.isEvent) {
112
+ traceData.activeSpans.delete(span.id);
113
+ if (traceData.activeSpans.size === 0) {
114
+ this.traceMap.delete(span.traceId);
115
+ }
116
+ return;
117
+ }
80
118
  this.logger.warn("Langfuse exporter: No Langfuse span found for span update/end", {
81
119
  traceId: span.traceId,
82
120
  spanId: span.id,
@@ -88,10 +126,15 @@ var LangfuseExporter = class {
88
126
  });
89
127
  return;
90
128
  }
91
- langfuseSpan.update(this.buildSpanPayload(span, false));
92
- if (isEnd && span.isRootSpan) {
93
- traceData.trace.update({ output: span.output });
94
- this.traceMap.delete(span.traceId);
129
+ langfuseSpan.update(this.buildSpanPayload(span, false, traceData));
130
+ if (isEnd) {
131
+ traceData.activeSpans.delete(span.id);
132
+ if (span.isRootSpan) {
133
+ traceData.trace.update({ output: span.output });
134
+ }
135
+ if (traceData.activeSpans.size === 0) {
136
+ this.traceMap.delete(span.traceId);
137
+ }
95
138
  }
96
139
  }
97
140
  async handleEventSpan(span) {
@@ -113,13 +156,37 @@ var LangfuseExporter = class {
113
156
  if (!langfuseParent) {
114
157
  return;
115
158
  }
116
- const payload = this.buildSpanPayload(span, true);
159
+ const payload = this.buildSpanPayload(span, true, traceData);
117
160
  const langfuseEvent = langfuseParent.event(payload);
118
161
  traceData.events.set(span.id, langfuseEvent);
162
+ if (!span.endTime) {
163
+ traceData.activeSpans.add(span.id);
164
+ }
119
165
  }
120
166
  initTrace(span) {
167
+ if (this.traceMap.has(span.traceId)) {
168
+ this.logger.debug("Langfuse exporter: Reusing existing trace from local map", {
169
+ traceId: span.traceId,
170
+ spanId: span.id,
171
+ spanName: span.name
172
+ });
173
+ return;
174
+ }
121
175
  const trace = this.client.trace(this.buildTracePayload(span));
122
- this.traceMap.set(span.traceId, { trace, spans: /* @__PURE__ */ new Map(), events: /* @__PURE__ */ new Map() });
176
+ const langfuseData = span.metadata?.langfuse;
177
+ const spanMetadata = /* @__PURE__ */ new Map();
178
+ spanMetadata.set(span.id, {
179
+ parentSpanId: void 0,
180
+ langfusePrompt: langfuseData?.prompt
181
+ });
182
+ this.traceMap.set(span.traceId, {
183
+ trace,
184
+ spans: /* @__PURE__ */ new Map(),
185
+ spanMetadata,
186
+ events: /* @__PURE__ */ new Map(),
187
+ activeSpans: /* @__PURE__ */ new Set(),
188
+ rootSpanId: span.id
189
+ });
123
190
  }
124
191
  getTraceData(options) {
125
192
  const { span, method } = options;
@@ -167,6 +234,7 @@ var LangfuseExporter = class {
167
234
  if (userId) payload.userId = userId;
168
235
  if (sessionId) payload.sessionId = sessionId;
169
236
  if (span.input) payload.input = span.input;
237
+ if (span.tags?.length) payload.tags = span.tags;
170
238
  payload.metadata = {
171
239
  spanType: span.type,
172
240
  ...span.attributes,
@@ -174,7 +242,23 @@ var LangfuseExporter = class {
174
242
  };
175
243
  return payload;
176
244
  }
177
- buildSpanPayload(span, isCreate) {
245
+ /**
246
+ * Look up the Langfuse prompt from the closest parent span that has one.
247
+ * This enables prompt inheritance for MODEL_GENERATION spans when the prompt
248
+ * is set on a parent span (e.g., AGENT_RUN) rather than directly on the generation.
249
+ */
250
+ findParentLangfusePrompt(traceData, span) {
251
+ let currentSpanId = span.parentSpanId;
252
+ while (currentSpanId) {
253
+ const parentMetadata = traceData.spanMetadata.get(currentSpanId);
254
+ if (parentMetadata?.langfusePrompt) {
255
+ return parentMetadata.langfusePrompt;
256
+ }
257
+ currentSpanId = parentMetadata?.parentSpanId;
258
+ }
259
+ return void 0;
260
+ }
261
+ buildSpanPayload(span, isCreate, traceData) {
178
262
  const payload = {};
179
263
  if (isCreate) {
180
264
  payload.id = span.id;
@@ -185,26 +269,51 @@ var LangfuseExporter = class {
185
269
  if (span.output !== void 0) payload.output = span.output;
186
270
  if (span.endTime !== void 0) payload.endTime = span.endTime;
187
271
  const attributes = span.attributes ?? {};
272
+ const resolvedTraceData = traceData ?? this.traceMap.get(span.traceId);
273
+ let inheritedLangfusePrompt;
274
+ if (span.type === observability$1.SpanType.MODEL_GENERATION && !span.metadata?.langfuse && resolvedTraceData) {
275
+ inheritedLangfusePrompt = this.findParentLangfusePrompt(resolvedTraceData, span);
276
+ }
277
+ const metadata = {
278
+ ...span.metadata,
279
+ ...inheritedLangfusePrompt ? { langfuse: { prompt: inheritedLangfusePrompt } } : {}
280
+ };
188
281
  const attributesToOmit = [];
189
- if (span.type === aiTracing.AISpanType.LLM_GENERATION) {
190
- const llmAttr = attributes;
191
- if (llmAttr.model !== void 0) {
192
- payload.model = llmAttr.model;
282
+ const metadataToOmit = [];
283
+ if (span.type === observability$1.SpanType.MODEL_GENERATION) {
284
+ const modelAttr = attributes;
285
+ if (modelAttr.model !== void 0) {
286
+ payload.model = modelAttr.model;
193
287
  attributesToOmit.push("model");
194
288
  }
195
- if (llmAttr.usage !== void 0) {
196
- payload.usage = llmAttr.usage;
289
+ if (modelAttr.usage !== void 0) {
290
+ payload.usageDetails = formatUsageMetrics(modelAttr.usage);
197
291
  attributesToOmit.push("usage");
198
292
  }
199
- if (llmAttr.parameters !== void 0) {
200
- payload.modelParameters = llmAttr.parameters;
293
+ if (modelAttr.parameters !== void 0) {
294
+ payload.modelParameters = modelAttr.parameters;
201
295
  attributesToOmit.push("parameters");
202
296
  }
297
+ const langfuseData = metadata.langfuse;
298
+ const promptData = langfuseData?.prompt;
299
+ const hasNameAndVersion = promptData?.name !== void 0 && promptData?.version !== void 0;
300
+ const hasId = promptData?.id !== void 0;
301
+ if (hasNameAndVersion || hasId) {
302
+ payload.prompt = {};
303
+ if (promptData?.name !== void 0) payload.prompt.name = promptData.name;
304
+ if (promptData?.version !== void 0) payload.prompt.version = promptData.version;
305
+ if (promptData?.id !== void 0) payload.prompt.id = promptData.id;
306
+ metadataToOmit.push("langfuse");
307
+ }
308
+ if (modelAttr.completionStartTime !== void 0) {
309
+ payload.completionStartTime = modelAttr.completionStartTime;
310
+ attributesToOmit.push("completionStartTime");
311
+ }
203
312
  }
204
313
  payload.metadata = {
205
314
  spanType: span.type,
206
- ...aiTracing.omitKeys(attributes, attributesToOmit),
207
- ...span.metadata
315
+ ...utils.omitKeys(attributes, attributesToOmit),
316
+ ...utils.omitKeys(metadata, metadataToOmit)
208
317
  };
209
318
  if (span.errorInfo) {
210
319
  payload.level = "ERROR";
@@ -212,14 +321,64 @@ var LangfuseExporter = class {
212
321
  }
213
322
  return payload;
214
323
  }
324
+ async addScoreToTrace({
325
+ traceId,
326
+ spanId,
327
+ score,
328
+ reason,
329
+ scorerName,
330
+ metadata
331
+ }) {
332
+ if (!this.client) return;
333
+ try {
334
+ await this.client.score({
335
+ id: `${traceId}-${scorerName}`,
336
+ traceId,
337
+ observationId: spanId,
338
+ name: scorerName,
339
+ value: score,
340
+ ...metadata?.sessionId ? { sessionId: metadata.sessionId } : {},
341
+ metadata: { ...reason ? { reason } : {} },
342
+ dataType: "NUMERIC"
343
+ });
344
+ } catch (error) {
345
+ this.logger.error("Langfuse exporter: Error adding score to trace", {
346
+ error,
347
+ traceId,
348
+ spanId,
349
+ scorerName
350
+ });
351
+ }
352
+ }
215
353
  async shutdown() {
216
354
  if (this.client) {
217
355
  await this.client.shutdownAsync();
218
356
  }
219
357
  this.traceMap.clear();
358
+ await super.shutdown();
220
359
  }
221
360
  };
222
361
 
362
+ // src/helpers.ts
363
+ function withLangfusePrompt(prompt) {
364
+ return (opts) => ({
365
+ ...opts,
366
+ metadata: {
367
+ ...opts.metadata,
368
+ langfuse: {
369
+ ...opts.metadata?.langfuse,
370
+ prompt: {
371
+ ...prompt.name !== void 0 && { name: prompt.name },
372
+ ...prompt.version !== void 0 && { version: prompt.version },
373
+ ...prompt.id !== void 0 && { id: prompt.id }
374
+ }
375
+ }
376
+ }
377
+ });
378
+ }
379
+
223
380
  exports.LangfuseExporter = LangfuseExporter;
381
+ exports.formatUsageMetrics = formatUsageMetrics;
382
+ exports.withLangfusePrompt = withLangfusePrompt;
224
383
  //# sourceMappingURL=index.cjs.map
225
384
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ai-tracing.ts"],"names":["ConsoleLogger","Langfuse","AISpanType","omitKeys"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Langfuse Exporter for Mastra AI Tracing\n *\n * This exporter sends tracing data to Langfuse for AI observability.\n * Root spans start traces in Langfuse.\n * LLM_GENERATION spans become Langfuse generations, all others become spans.\n */\n\nimport type {\n AITracingExporter,\n AITracingEvent,\n AnyExportedAISpan,\n LLMGenerationAttributes,\n} from '@mastra/core/ai-tracing';\nimport { AISpanType, omitKeys } from '@mastra/core/ai-tracing';\nimport { ConsoleLogger } from '@mastra/core/logger';\nimport { Langfuse } from 'langfuse';\nimport type { LangfuseTraceClient, LangfuseSpanClient, LangfuseGenerationClient, LangfuseEventClient } from 'langfuse';\n\nexport interface LangfuseExporterConfig {\n /** Langfuse API key */\n publicKey?: string;\n /** Langfuse secret key */\n secretKey?: string;\n /** Langfuse host URL */\n baseUrl?: string;\n /** Enable realtime mode - flushes after each event for immediate visibility */\n realtime?: boolean;\n /** Logger level for diagnostic messages (default: 'warn') */\n logLevel?: 'debug' | 'info' | 'warn' | 'error';\n /** Additional options to pass to the Langfuse client */\n options?: any;\n}\n\ntype TraceData = {\n trace: LangfuseTraceClient; // Langfuse trace object\n spans: Map<string, LangfuseSpanClient | LangfuseGenerationClient>; // Maps span.id to Langfuse span/generation\n events: Map<string, LangfuseEventClient>; // Maps span.id to Langfuse event\n};\n\ntype LangfuseParent = LangfuseTraceClient | LangfuseSpanClient | LangfuseGenerationClient | LangfuseEventClient;\n\nexport class LangfuseExporter implements AITracingExporter {\n name = 'langfuse';\n private client: Langfuse;\n private realtime: boolean;\n private traceMap = new Map<string, TraceData>();\n private logger: ConsoleLogger;\n\n constructor(config: LangfuseExporterConfig) {\n this.realtime = config.realtime ?? false;\n this.logger = new ConsoleLogger({ level: config.logLevel ?? 'warn' });\n\n if (!config.publicKey || !config.secretKey) {\n this.logger.error('LangfuseExporter: Missing required credentials, exporter will be disabled', {\n hasPublicKey: !!config.publicKey,\n hasSecretKey: !!config.secretKey,\n });\n // Create a no-op client to prevent runtime errors\n this.client = null as any;\n return;\n }\n\n this.client = new Langfuse({\n publicKey: config.publicKey,\n secretKey: config.secretKey,\n baseUrl: config.baseUrl,\n ...config.options,\n });\n }\n\n async exportEvent(event: AITracingEvent): Promise<void> {\n if (!this.client) {\n // Exporter is disabled due to missing credentials\n return;\n }\n\n if (event.exportedSpan.isEvent) {\n await this.handleEventSpan(event.exportedSpan);\n return;\n }\n\n switch (event.type) {\n case 'span_started':\n await this.handleSpanStarted(event.exportedSpan);\n break;\n case 'span_updated':\n await this.handleSpanUpdateOrEnd(event.exportedSpan, false);\n break;\n case 'span_ended':\n await this.handleSpanUpdateOrEnd(event.exportedSpan, true);\n break;\n }\n\n // Flush immediately in realtime mode for instant visibility\n if (this.realtime) {\n await this.client.flushAsync();\n }\n }\n\n private async handleSpanStarted(span: AnyExportedAISpan): Promise<void> {\n if (span.isRootSpan) {\n this.initTrace(span);\n }\n const method = 'handleSpanStarted';\n\n const traceData = this.getTraceData({ span, method });\n if (!traceData) {\n return;\n }\n\n const langfuseParent = this.getLangfuseParent({ traceData, span, method });\n if (!langfuseParent) {\n return;\n }\n\n const payload = this.buildSpanPayload(span, true);\n\n const langfuseSpan =\n span.type === AISpanType.LLM_GENERATION ? langfuseParent.generation(payload) : langfuseParent.span(payload);\n\n traceData.spans.set(span.id, langfuseSpan);\n }\n\n private async handleSpanUpdateOrEnd(span: AnyExportedAISpan, isEnd: boolean): Promise<void> {\n const method = isEnd ? 'handleSpanEnd' : 'handleSpanUpdate';\n\n const traceData = this.getTraceData({ span, method });\n if (!traceData) {\n return;\n }\n\n const langfuseSpan = traceData.spans.get(span.id);\n if (!langfuseSpan) {\n this.logger.warn('Langfuse exporter: No Langfuse span found for span update/end', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n spanType: span.type,\n isRootSpan: span.isRootSpan,\n parentSpanId: span.parentSpanId,\n method,\n });\n return;\n }\n\n // use update for both update & end, so that we can use the\n // end time we set when ending the span.\n langfuseSpan.update(this.buildSpanPayload(span, false));\n\n if (isEnd && span.isRootSpan) {\n traceData.trace.update({ output: span.output });\n this.traceMap.delete(span.traceId);\n }\n }\n\n private async handleEventSpan(span: AnyExportedAISpan): Promise<void> {\n if (span.isRootSpan) {\n this.logger.debug('Langfuse exporter: Creating trace', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n method: 'handleEventSpan',\n });\n this.initTrace(span);\n }\n const method = 'handleEventSpan';\n\n const traceData = this.getTraceData({ span, method });\n if (!traceData) {\n return;\n }\n\n const langfuseParent = this.getLangfuseParent({ traceData, span, method });\n if (!langfuseParent) {\n return;\n }\n\n const payload = this.buildSpanPayload(span, true);\n\n const langfuseEvent = langfuseParent.event(payload);\n\n traceData.events.set(span.id, langfuseEvent);\n }\n\n private initTrace(span: AnyExportedAISpan): void {\n const trace = this.client.trace(this.buildTracePayload(span));\n this.traceMap.set(span.traceId, { trace, spans: new Map(), events: new Map() });\n }\n\n private getTraceData(options: { span: AnyExportedAISpan; method: string }): TraceData | undefined {\n const { span, method } = options;\n if (this.traceMap.has(span.traceId)) {\n return this.traceMap.get(span.traceId);\n }\n this.logger.warn('Langfuse exporter: No trace data found for span', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n spanType: span.type,\n isRootSpan: span.isRootSpan,\n parentSpanId: span.parentSpanId,\n method,\n });\n }\n\n private getLangfuseParent(options: {\n traceData: TraceData;\n span: AnyExportedAISpan;\n method: string;\n }): LangfuseParent | undefined {\n const { traceData, span, method } = options;\n\n const parentId = span.parentSpanId;\n if (!parentId) {\n return traceData.trace;\n }\n if (traceData.spans.has(parentId)) {\n return traceData.spans.get(parentId);\n }\n if (traceData.events.has(parentId)) {\n return traceData.events.get(parentId);\n }\n this.logger.warn('Langfuse exporter: No parent data found for span', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n spanType: span.type,\n isRootSpan: span.isRootSpan,\n parentSpanId: span.parentSpanId,\n method,\n });\n }\n\n private buildTracePayload(span: AnyExportedAISpan): Record<string, any> {\n const payload: Record<string, any> = {\n id: span.traceId,\n name: span.name,\n };\n\n const { userId, sessionId, ...remainingMetadata } = span.metadata ?? {};\n\n if (userId) payload.userId = userId;\n if (sessionId) payload.sessionId = sessionId;\n if (span.input) payload.input = span.input;\n\n payload.metadata = {\n spanType: span.type,\n ...span.attributes,\n ...remainingMetadata,\n };\n\n return payload;\n }\n\n private buildSpanPayload(span: AnyExportedAISpan, isCreate: boolean): Record<string, any> {\n const payload: Record<string, any> = {};\n\n if (isCreate) {\n payload.id = span.id;\n payload.name = span.name;\n payload.startTime = span.startTime;\n if (span.input !== undefined) payload.input = span.input;\n }\n\n if (span.output !== undefined) payload.output = span.output;\n if (span.endTime !== undefined) payload.endTime = span.endTime;\n\n const attributes = (span.attributes ?? {}) as Record<string, any>;\n\n // Strip special fields from metadata if used in top-level keys\n const attributesToOmit: string[] = [];\n\n if (span.type === AISpanType.LLM_GENERATION) {\n const llmAttr = attributes as LLMGenerationAttributes;\n\n if (llmAttr.model !== undefined) {\n payload.model = llmAttr.model;\n attributesToOmit.push('model');\n }\n\n if (llmAttr.usage !== undefined) {\n payload.usage = llmAttr.usage;\n attributesToOmit.push('usage');\n }\n\n if (llmAttr.parameters !== undefined) {\n payload.modelParameters = llmAttr.parameters;\n attributesToOmit.push('parameters');\n }\n }\n\n payload.metadata = {\n spanType: span.type,\n ...omitKeys(attributes, attributesToOmit),\n ...span.metadata,\n };\n\n if (span.errorInfo) {\n payload.level = 'ERROR';\n payload.statusMessage = span.errorInfo.message;\n }\n\n return payload;\n }\n\n async shutdown(): Promise<void> {\n if (this.client) {\n await this.client.shutdownAsync();\n }\n this.traceMap.clear();\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/tracing.ts","../src/helpers.ts"],"names":["BaseExporter","Langfuse","SpanType","omitKeys"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Langfuse Exporter for Mastra Observability\n *\n * This exporter sends observability data to Langfuse.\n * Root spans start traces in Langfuse.\n * MODEL_GENERATION spans become Langfuse generations, all others become spans.\n */\n\nimport type { TracingEvent, AnyExportedSpan, ModelGenerationAttributes, UsageStats } from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { BaseExporter } from '@mastra/observability';\nimport type { BaseExporterConfig } from '@mastra/observability';\nimport { Langfuse } from 'langfuse';\nimport type { LangfuseTraceClient, LangfuseSpanClient, LangfuseGenerationClient, LangfuseEventClient } from 'langfuse';\n\nexport interface LangfuseExporterConfig extends BaseExporterConfig {\n /** Langfuse API key */\n publicKey?: string;\n /** Langfuse secret key */\n secretKey?: string;\n /** Langfuse host URL */\n baseUrl?: string;\n /** Enable realtime mode - flushes after each event for immediate visibility */\n realtime?: boolean;\n /** Additional options to pass to the Langfuse client */\n options?: any;\n}\n\ntype LangfusePromptData = { name?: string; version?: number; id?: string };\n\ntype SpanMetadata = {\n parentSpanId?: string;\n langfusePrompt?: LangfusePromptData;\n};\n\ntype TraceData = {\n trace: LangfuseTraceClient; // Langfuse trace object\n spans: Map<string, LangfuseSpanClient | LangfuseGenerationClient>; // Maps span.id to Langfuse span/generation\n spanMetadata: Map<string, SpanMetadata>; // Maps span.id to span metadata for prompt inheritance\n events: Map<string, LangfuseEventClient>; // Maps span.id to Langfuse event\n activeSpans: Set<string>; // Tracks which spans haven't ended yet\n rootSpanId?: string; // Track the root span ID\n};\n\ntype LangfuseParent = LangfuseTraceClient | LangfuseSpanClient | LangfuseGenerationClient | LangfuseEventClient;\n\n/**\n * Token usage format compatible with Langfuse.\n */\nexport interface LangfuseUsageMetrics {\n input?: number;\n output?: number;\n total?: number;\n reasoning?: number;\n cache_read_input_tokens?: number;\n cache_write_input_tokens?: number;\n}\n\n/**\n * Formats UsageStats to Langfuse's expected format.\n */\nexport function formatUsageMetrics(usage?: UsageStats): LangfuseUsageMetrics {\n if (!usage) return {};\n\n const metrics: LangfuseUsageMetrics = {};\n\n if (usage.inputTokens !== undefined) {\n metrics.input = usage.inputTokens;\n\n if (usage.inputDetails?.cacheWrite !== undefined) {\n metrics.cache_write_input_tokens = usage.inputDetails.cacheWrite;\n metrics.input -= metrics.cache_write_input_tokens;\n }\n }\n\n if (usage.inputDetails?.cacheRead !== undefined) {\n metrics.cache_read_input_tokens = usage.inputDetails.cacheRead;\n }\n\n if (usage.outputTokens !== undefined) {\n metrics.output = usage.outputTokens;\n }\n\n if (usage.outputDetails?.reasoning !== undefined) {\n metrics.reasoning = usage.outputDetails.reasoning;\n }\n\n if (metrics.input && metrics.output) {\n metrics.total = metrics.input + metrics.output;\n if (metrics.cache_write_input_tokens) {\n metrics.total += metrics.cache_write_input_tokens;\n }\n }\n\n return metrics;\n}\n\nexport class LangfuseExporter extends BaseExporter {\n name = 'langfuse';\n private client: Langfuse;\n private realtime: boolean;\n private traceMap = new Map<string, TraceData>();\n\n constructor(config: LangfuseExporterConfig) {\n super(config);\n\n this.realtime = config.realtime ?? false;\n\n if (!config.publicKey || !config.secretKey) {\n this.setDisabled(\n `Missing required credentials (publicKey: ${!!config.publicKey}, secretKey: ${!!config.secretKey})`,\n );\n // Create a no-op client to prevent runtime errors\n this.client = null as any;\n return;\n }\n\n this.client = new Langfuse({\n publicKey: config.publicKey,\n secretKey: config.secretKey,\n baseUrl: config.baseUrl,\n ...config.options,\n });\n }\n\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n if (event.exportedSpan.isEvent) {\n await this.handleEventSpan(event.exportedSpan);\n return;\n }\n\n switch (event.type) {\n case 'span_started':\n await this.handleSpanStarted(event.exportedSpan);\n break;\n case 'span_updated':\n await this.handleSpanUpdateOrEnd(event.exportedSpan, false);\n break;\n case 'span_ended':\n await this.handleSpanUpdateOrEnd(event.exportedSpan, true);\n break;\n }\n\n // Flush immediately in realtime mode for instant visibility\n if (this.realtime) {\n await this.client.flushAsync();\n }\n }\n\n private async handleSpanStarted(span: AnyExportedSpan): Promise<void> {\n if (span.isRootSpan) {\n this.initTrace(span);\n }\n const method = 'handleSpanStarted';\n\n const traceData = this.getTraceData({ span, method });\n if (!traceData) {\n return;\n }\n\n // Store span metadata for prompt inheritance lookup (for non-root spans)\n if (!span.isRootSpan) {\n const langfuseData = span.metadata?.langfuse as { prompt?: LangfusePromptData } | undefined;\n traceData.spanMetadata.set(span.id, {\n parentSpanId: span.parentSpanId,\n langfusePrompt: langfuseData?.prompt,\n });\n }\n\n const langfuseParent = this.getLangfuseParent({ traceData, span, method });\n if (!langfuseParent) {\n return;\n }\n\n const payload = this.buildSpanPayload(span, true, traceData);\n\n const langfuseSpan =\n span.type === SpanType.MODEL_GENERATION ? langfuseParent.generation(payload) : langfuseParent.span(payload);\n\n traceData.spans.set(span.id, langfuseSpan);\n traceData.activeSpans.add(span.id); // Track as active\n }\n\n private async handleSpanUpdateOrEnd(span: AnyExportedSpan, isEnd: boolean): Promise<void> {\n const method = isEnd ? 'handleSpanEnd' : 'handleSpanUpdate';\n\n const traceData = this.getTraceData({ span, method });\n if (!traceData) {\n return;\n }\n\n const langfuseSpan = traceData.spans.get(span.id);\n if (!langfuseSpan) {\n // For event spans that only send SPAN_ENDED, we might not have the span yet\n if (isEnd && span.isEvent) {\n // Just make sure it's not in active spans\n traceData.activeSpans.delete(span.id);\n if (traceData.activeSpans.size === 0) {\n this.traceMap.delete(span.traceId);\n }\n return;\n }\n\n this.logger.warn('Langfuse exporter: No Langfuse span found for span update/end', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n spanType: span.type,\n isRootSpan: span.isRootSpan,\n parentSpanId: span.parentSpanId,\n method,\n });\n return;\n }\n\n // use update for both update & end, so that we can use the\n // end time we set when ending the span.\n langfuseSpan.update(this.buildSpanPayload(span, false, traceData));\n\n if (isEnd) {\n // Remove from active spans\n traceData.activeSpans.delete(span.id);\n\n if (span.isRootSpan) {\n traceData.trace.update({ output: span.output });\n }\n\n // Only clean up the trace when ALL spans have ended\n if (traceData.activeSpans.size === 0) {\n this.traceMap.delete(span.traceId);\n }\n }\n }\n\n private async handleEventSpan(span: AnyExportedSpan): Promise<void> {\n if (span.isRootSpan) {\n this.logger.debug('Langfuse exporter: Creating trace', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n method: 'handleEventSpan',\n });\n this.initTrace(span);\n }\n const method = 'handleEventSpan';\n\n const traceData = this.getTraceData({ span, method });\n if (!traceData) {\n return;\n }\n\n const langfuseParent = this.getLangfuseParent({ traceData, span, method });\n if (!langfuseParent) {\n return;\n }\n\n const payload = this.buildSpanPayload(span, true, traceData);\n\n const langfuseEvent = langfuseParent.event(payload);\n\n traceData.events.set(span.id, langfuseEvent);\n\n // Event spans are typically immediately ended, but let's track them properly\n if (!span.endTime) {\n traceData.activeSpans.add(span.id);\n }\n }\n\n private initTrace(span: AnyExportedSpan): void {\n // Check if trace already exists in our local traceMap\n // This allows multiple root spans (e.g., from multiple agent.stream calls)\n // to be grouped under the same Langfuse trace\n if (this.traceMap.has(span.traceId)) {\n this.logger.debug('Langfuse exporter: Reusing existing trace from local map', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n });\n return; // Reuse existing trace\n }\n\n // Note: If the traceId already exists in Langfuse (e.g., from a previous server instance\n // or session), the Langfuse SDK handles this gracefully. Calling client.trace() with\n // an existing ID is idempotent - it will update/continue the existing trace rather than\n // failing or creating a duplicate. This is by design for distributed tracing scenarios.\n // See: https://langfuse.com/docs/tracing-features/trace-ids\n const trace = this.client.trace(this.buildTracePayload(span));\n\n // Extract langfuse prompt data from root span\n const langfuseData = span.metadata?.langfuse as { prompt?: LangfusePromptData } | undefined;\n const spanMetadata = new Map<string, SpanMetadata>();\n\n // Store root span metadata for prompt inheritance\n spanMetadata.set(span.id, {\n parentSpanId: undefined,\n langfusePrompt: langfuseData?.prompt,\n });\n\n this.traceMap.set(span.traceId, {\n trace,\n spans: new Map(),\n spanMetadata,\n events: new Map(),\n activeSpans: new Set(),\n rootSpanId: span.id,\n });\n }\n\n private getTraceData(options: { span: AnyExportedSpan; method: string }): TraceData | undefined {\n const { span, method } = options;\n\n if (this.traceMap.has(span.traceId)) {\n return this.traceMap.get(span.traceId);\n }\n\n this.logger.warn('Langfuse exporter: No trace data found for span', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n spanType: span.type,\n isRootSpan: span.isRootSpan,\n parentSpanId: span.parentSpanId,\n method,\n });\n }\n\n private getLangfuseParent(options: {\n traceData: TraceData;\n span: AnyExportedSpan;\n method: string;\n }): LangfuseParent | undefined {\n const { traceData, span, method } = options;\n\n const parentId = span.parentSpanId;\n if (!parentId) {\n return traceData.trace;\n }\n if (traceData.spans.has(parentId)) {\n return traceData.spans.get(parentId);\n }\n if (traceData.events.has(parentId)) {\n return traceData.events.get(parentId);\n }\n this.logger.warn('Langfuse exporter: No parent data found for span', {\n traceId: span.traceId,\n spanId: span.id,\n spanName: span.name,\n spanType: span.type,\n isRootSpan: span.isRootSpan,\n parentSpanId: span.parentSpanId,\n method,\n });\n }\n\n private buildTracePayload(span: AnyExportedSpan): Record<string, any> {\n const payload: Record<string, any> = {\n id: span.traceId,\n name: span.name,\n };\n\n const { userId, sessionId, ...remainingMetadata } = span.metadata ?? {};\n\n if (userId) payload.userId = userId;\n if (sessionId) payload.sessionId = sessionId;\n if (span.input) payload.input = span.input;\n // Include tags if present (only for root spans, which is always the case here)\n if (span.tags?.length) payload.tags = span.tags;\n\n payload.metadata = {\n spanType: span.type,\n ...span.attributes,\n ...remainingMetadata,\n };\n\n return payload;\n }\n\n /**\n * Look up the Langfuse prompt from the closest parent span that has one.\n * This enables prompt inheritance for MODEL_GENERATION spans when the prompt\n * is set on a parent span (e.g., AGENT_RUN) rather than directly on the generation.\n */\n private findParentLangfusePrompt(traceData: TraceData, span: AnyExportedSpan): LangfusePromptData | undefined {\n let currentSpanId = span.parentSpanId;\n\n while (currentSpanId) {\n const parentMetadata = traceData.spanMetadata.get(currentSpanId);\n if (parentMetadata?.langfusePrompt) {\n return parentMetadata.langfusePrompt;\n }\n currentSpanId = parentMetadata?.parentSpanId;\n }\n\n return undefined;\n }\n\n private buildSpanPayload(span: AnyExportedSpan, isCreate: boolean, traceData?: TraceData): Record<string, any> {\n const payload: Record<string, any> = {};\n\n if (isCreate) {\n payload.id = span.id;\n payload.name = span.name;\n payload.startTime = span.startTime;\n if (span.input !== undefined) payload.input = span.input;\n }\n\n if (span.output !== undefined) payload.output = span.output;\n if (span.endTime !== undefined) payload.endTime = span.endTime;\n\n const attributes = (span.attributes ?? {}) as Record<string, any>;\n\n // For MODEL_GENERATION spans without langfuse metadata, look up the closest\n // parent span that has langfuse prompt data. This enables prompt linking when:\n // - A workflow calls multiple agents, each with different prompts\n // - Nested agents have different prompts\n // - The prompt is set on AGENT_RUN but MODEL_GENERATION inherits it\n const resolvedTraceData = traceData ?? this.traceMap.get(span.traceId);\n let inheritedLangfusePrompt: LangfusePromptData | undefined;\n\n if (span.type === SpanType.MODEL_GENERATION && !span.metadata?.langfuse && resolvedTraceData) {\n inheritedLangfusePrompt = this.findParentLangfusePrompt(resolvedTraceData, span);\n }\n\n const metadata: Record<string, any> = {\n ...span.metadata,\n ...(inheritedLangfusePrompt ? { langfuse: { prompt: inheritedLangfusePrompt } } : {}),\n };\n\n // Strip special fields from metadata if used in top-level keys\n const attributesToOmit: string[] = [];\n const metadataToOmit: string[] = [];\n\n if (span.type === SpanType.MODEL_GENERATION) {\n const modelAttr = attributes as ModelGenerationAttributes;\n\n if (modelAttr.model !== undefined) {\n payload.model = modelAttr.model;\n attributesToOmit.push('model');\n }\n\n if (modelAttr.usage !== undefined) {\n payload.usageDetails = formatUsageMetrics(modelAttr.usage);\n attributesToOmit.push('usage');\n }\n\n if (modelAttr.parameters !== undefined) {\n payload.modelParameters = modelAttr.parameters;\n attributesToOmit.push('parameters');\n }\n\n // Handle Langfuse prompt linking\n // Users can set metadata.langfuse.prompt to link generations to Langfuse Prompt Management\n // Supported formats:\n // - { id } - link by prompt UUID alone\n // - { name, version } - link by name and version\n // - { name, version, id } - link with all fields\n const langfuseData = metadata.langfuse as\n | { prompt?: { name?: string; version?: number; id?: string } }\n | undefined;\n const promptData = langfuseData?.prompt;\n const hasNameAndVersion = promptData?.name !== undefined && promptData?.version !== undefined;\n const hasId = promptData?.id !== undefined;\n\n if (hasNameAndVersion || hasId) {\n payload.prompt = {};\n\n if (promptData?.name !== undefined) payload.prompt.name = promptData.name;\n if (promptData?.version !== undefined) payload.prompt.version = promptData.version;\n if (promptData?.id !== undefined) payload.prompt.id = promptData.id;\n\n metadataToOmit.push('langfuse');\n }\n\n // completionStartTime is used by Langfuse to calculate time-to-first-token (TTFT)\n if (modelAttr.completionStartTime !== undefined) {\n payload.completionStartTime = modelAttr.completionStartTime;\n attributesToOmit.push('completionStartTime');\n }\n }\n\n payload.metadata = {\n spanType: span.type,\n ...omitKeys(attributes, attributesToOmit),\n ...omitKeys(metadata, metadataToOmit),\n };\n\n if (span.errorInfo) {\n payload.level = 'ERROR';\n payload.statusMessage = span.errorInfo.message;\n }\n\n return payload;\n }\n\n async addScoreToTrace({\n traceId,\n spanId,\n score,\n reason,\n scorerName,\n metadata,\n }: {\n traceId: string;\n spanId?: string;\n score: number;\n reason?: string;\n scorerName: string;\n metadata?: Record<string, any>;\n }): Promise<void> {\n if (!this.client) return;\n\n try {\n await this.client.score({\n id: `${traceId}-${scorerName}`,\n traceId,\n observationId: spanId,\n name: scorerName,\n value: score,\n ...(metadata?.sessionId ? { sessionId: metadata.sessionId } : {}),\n metadata: { ...(reason ? { reason } : {}) },\n dataType: 'NUMERIC',\n });\n } catch (error) {\n this.logger.error('Langfuse exporter: Error adding score to trace', {\n error,\n traceId,\n spanId,\n scorerName,\n });\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.client) {\n await this.client.shutdownAsync();\n }\n this.traceMap.clear();\n await super.shutdown();\n }\n}\n","/**\n * Langfuse Tracing Options Helpers\n *\n * These helpers integrate with the `buildTracingOptions` pattern from\n * `@mastra/observability` to add Langfuse-specific tracing features.\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangfusePrompt } from '@mastra/langfuse';\n *\n * const prompt = await langfuse.getPrompt('my-prompt');\n *\n * const agent = new Agent({\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(withLangfusePrompt(prompt)),\n * },\n * });\n * ```\n */\n\nimport type { TracingOptionsUpdater } from '@mastra/observability';\n\n/**\n * Langfuse prompt input - accepts either a Langfuse SDK prompt object\n * or manual fields.\n */\nexport interface LangfusePromptInput {\n /** Prompt name */\n name?: string;\n /** Prompt version */\n version?: number;\n /** Prompt UUID */\n id?: string;\n}\n\n/**\n * Adds Langfuse prompt metadata to the tracing options\n * to enable Langfuse Prompt Tracing.\n *\n * The metadata is added under `metadata.langfuse.prompt` and includes:\n * - `name` - Prompt name\n * - `version` - Prompt version\n * - `id` - Prompt UUID\n *\n * All fields are deeply merged with any existing metadata.\n *\n * @param prompt - A Langfuse prompt object (from `langfuse.getPrompt()`) or manual fields\n * @returns A TracingOptionsUpdater function for use with `buildTracingOptions`\n *\n * @example\n * ```typescript\n * import { buildTracingOptions } from '@mastra/observability';\n * import { withLangfusePrompt } from '@mastra/langfuse';\n * import { Langfuse } from 'langfuse';\n *\n * const langfuse = new Langfuse();\n * const prompt = await langfuse.getPrompt('customer-support');\n *\n * // Use with buildTracingOptions\n * const tracingOptions = buildTracingOptions(\n * withLangfusePrompt(prompt),\n * );\n *\n * // Or directly in agent config\n * const agent = new Agent({\n * name: 'support-agent',\n * instructions: prompt.prompt,\n * model: openai('gpt-4o'),\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(withLangfusePrompt(prompt)),\n * },\n * });\n *\n * // Manual fields also work\n * const tracingOptions = buildTracingOptions(\n * withLangfusePrompt({ name: 'my-prompt', version: 1 }),\n * );\n * ```\n */\nexport function withLangfusePrompt(prompt: LangfusePromptInput): TracingOptionsUpdater {\n return opts => ({\n ...opts,\n metadata: {\n ...opts.metadata,\n langfuse: {\n ...(opts.metadata?.langfuse as Record<string, unknown>),\n prompt: {\n ...(prompt.name !== undefined && { name: prompt.name }),\n ...(prompt.version !== undefined && { version: prompt.version }),\n ...(prompt.id !== undefined && { id: prompt.id }),\n },\n },\n },\n });\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -2,7 +2,8 @@
2
2
  * Langfuse Observability Provider for Mastra
3
3
  *
4
4
  * This package provides Langfuse-specific observability features for Mastra applications.
5
- * Currently includes AI tracing support with plans for additional observability features.
5
+ * Currently includes tracing support with plans for additional observability features.
6
6
  */
7
- export * from './ai-tracing.js';
7
+ export * from './tracing.js';
8
+ export * from './helpers.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,WAAW,CAAC;AAG1B,cAAc,WAAW,CAAC"}