@mastra/langfuse 1.4.5 → 1.4.6

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
@@ -1,298 +1,304 @@
1
- import { LangfuseClient } from '@langfuse/client';
2
- import { LangfuseSpanProcessor } from '@langfuse/otel';
3
- import { TracingEventType, SpanType } from '@mastra/core/observability';
4
- import { BaseExporter } from '@mastra/observability';
5
- import { SpanConverter } from '@mastra/otel-exporter';
6
-
7
- // src/tracing.ts
8
- var LOG_PREFIX = "[LangfuseExporter]";
9
- var LANGFUSE_DEFAULT_BASE_URL = "https://cloud.langfuse.com";
1
+ import { LangfuseClient } from "@langfuse/client";
2
+ import { LangfuseSpanProcessor } from "@langfuse/otel";
3
+ import { SpanType, TracingEventType } from "@mastra/core/observability";
4
+ import { BaseExporter } from "@mastra/observability";
5
+ import { SpanConverter } from "@mastra/otel-exporter";
6
+ //#region src/tracing.ts
7
+ /**
8
+ * Langfuse Exporter for Mastra Observability
9
+ *
10
+ * Sends observability data to Langfuse using the official @langfuse/otel span processor
11
+ * and @langfuse/client for non-tracing features (scoring, prompt management, evaluations).
12
+ *
13
+ * @see https://langfuse.com/docs/observability/sdk/typescript/overview
14
+ */
15
+ const LOG_PREFIX = "[LangfuseExporter]";
16
+ const LANGFUSE_DEFAULT_BASE_URL = "https://cloud.langfuse.com";
10
17
  var LangfuseExporter = class extends BaseExporter {
11
- name = "langfuse";
12
- #processor;
13
- #client;
14
- #spanConverter;
15
- #realtime;
16
- #environment;
17
- #release;
18
- constructor(config = {}) {
19
- super(config);
20
- const publicKey = config.publicKey ?? process.env.LANGFUSE_PUBLIC_KEY;
21
- const secretKey = config.secretKey ?? process.env.LANGFUSE_SECRET_KEY;
22
- const baseUrl = stripTrailingSlashes(config.baseUrl ?? process.env.LANGFUSE_BASE_URL ?? LANGFUSE_DEFAULT_BASE_URL);
23
- this.#realtime = config.realtime ?? false;
24
- if (!publicKey || !secretKey) {
25
- const publicKeySource = config.publicKey ? "from config" : process.env.LANGFUSE_PUBLIC_KEY ? "from env" : "missing";
26
- const secretKeySource = config.secretKey ? "from config" : process.env.LANGFUSE_SECRET_KEY ? "from env" : "missing";
27
- this.setDisabled(
28
- `${LOG_PREFIX} Missing required credentials (publicKey: ${publicKeySource}, secretKey: ${secretKeySource}). Set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY environment variables or pass them in config.`
29
- );
30
- return;
31
- }
32
- this.#processor = new LangfuseSpanProcessor({
33
- publicKey,
34
- secretKey,
35
- baseUrl,
36
- environment: config.environment,
37
- release: config.release,
38
- exportMode: this.#realtime ? "immediate" : "batched",
39
- flushAt: config.flushAt,
40
- flushInterval: config.flushInterval,
41
- // Export all spans — the default filter only passes spans with gen_ai.* attributes
42
- // or known LLM instrumentation scopes, but Mastra spans use mastra.* attributes.
43
- shouldExportSpan: () => true
44
- });
45
- this.#client = new LangfuseClient({
46
- publicKey,
47
- secretKey,
48
- baseUrl
49
- });
50
- this.#environment = config.environment ?? process.env.LANGFUSE_TRACING_ENVIRONMENT;
51
- this.#release = config.release ?? process.env.LANGFUSE_RELEASE;
52
- }
53
- init(options) {
54
- this.#spanConverter = new SpanConverter({
55
- packageName: "@mastra/langfuse",
56
- serviceName: options.config?.serviceName,
57
- format: "GenAI_v1_38_0"
58
- });
59
- }
60
- async _exportTracingEvent(event) {
61
- if (event.type !== TracingEventType.SPAN_ENDED) return;
62
- if (!this.#processor) return;
63
- await this.exportSpan(event.exportedSpan);
64
- }
65
- async exportSpan(span) {
66
- if (!this.#spanConverter) {
67
- this.#spanConverter = new SpanConverter({
68
- packageName: "@mastra/langfuse",
69
- serviceName: "mastra-service",
70
- format: "GenAI_v1_38_0"
71
- });
72
- }
73
- try {
74
- const otelSpan = await this.#spanConverter.convertSpan(span);
75
- mapMastraToLangfuseAttributes(otelSpan.attributes, span, this.#environment, this.#release);
76
- this.#processor.onEnd(otelSpan);
77
- } catch (error) {
78
- this.logger.error(`${LOG_PREFIX} Failed to export span ${span.id}:`, error);
79
- }
80
- }
81
- /**
82
- * The LangfuseClient instance for advanced Langfuse features.
83
- * Use this for prompt management, evaluations, datasets, and direct API access.
84
- */
85
- get client() {
86
- return this.#client;
87
- }
88
- /**
89
- * Submit a score to Langfuse. Used by both the new `onScoreEvent` path and the
90
- * deprecated `addScoreToTrace` wrapper.
91
- */
92
- submitScore(args) {
93
- if (!this.#client) return;
94
- const { id, traceId, spanId, name, value, comment, metadata } = args;
95
- try {
96
- this.#client.score.create({
97
- id,
98
- traceId,
99
- ...spanId ? { observationId: spanId } : {},
100
- name,
101
- value,
102
- ...comment ? { comment } : {},
103
- ...metadata ? { metadata } : {},
104
- dataType: "NUMERIC"
105
- });
106
- } catch (error) {
107
- this.logger.error(`${LOG_PREFIX} Error submitting score`, {
108
- error,
109
- traceId,
110
- spanId,
111
- name
112
- });
113
- }
114
- }
115
- async onScoreEvent(event) {
116
- const { score } = event;
117
- if (!score.traceId) return;
118
- this.submitScore({
119
- id: score.scoreId,
120
- traceId: score.traceId,
121
- spanId: score.spanId,
122
- name: score.scorerName ?? score.scorerId,
123
- value: score.score,
124
- comment: score.reason,
125
- metadata: score.metadata
126
- });
127
- }
128
- /**
129
- * @deprecated Use the observability score event pipeline (`mastra.observability.addScore`)
130
- * instead. This method is preserved for backwards compatibility and forwards to the same
131
- * underlying client call as `onScoreEvent`.
132
- */
133
- async addScoreToTrace({
134
- traceId,
135
- spanId,
136
- score,
137
- reason,
138
- scorerName,
139
- metadata
140
- }) {
141
- this.submitScore({
142
- id: `${traceId}-${spanId || ""}-${scorerName}`,
143
- traceId,
144
- spanId,
145
- name: scorerName,
146
- value: score,
147
- comment: reason,
148
- metadata
149
- });
150
- }
151
- async flush() {
152
- await Promise.all([this.#processor?.forceFlush(), this.#client?.flush()]);
153
- }
154
- async shutdown() {
155
- await Promise.all([this.#processor?.shutdown(), this.#client?.shutdown()]);
156
- }
18
+ name = "langfuse";
19
+ #processor;
20
+ #client;
21
+ #spanConverter;
22
+ #realtime;
23
+ #environment;
24
+ #release;
25
+ constructor(config = {}) {
26
+ super(config);
27
+ const publicKey = config.publicKey ?? process.env.LANGFUSE_PUBLIC_KEY;
28
+ const secretKey = config.secretKey ?? process.env.LANGFUSE_SECRET_KEY;
29
+ const baseUrl = stripTrailingSlashes(config.baseUrl ?? process.env.LANGFUSE_BASE_URL ?? "https://cloud.langfuse.com");
30
+ this.#realtime = config.realtime ?? false;
31
+ if (!publicKey || !secretKey) {
32
+ const publicKeySource = config.publicKey ? "from config" : process.env.LANGFUSE_PUBLIC_KEY ? "from env" : "missing";
33
+ const secretKeySource = config.secretKey ? "from config" : process.env.LANGFUSE_SECRET_KEY ? "from env" : "missing";
34
+ this.setDisabled(`${LOG_PREFIX} Missing required credentials (publicKey: ${publicKeySource}, secretKey: ${secretKeySource}). Set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY environment variables or pass them in config.`);
35
+ return;
36
+ }
37
+ this.#processor = new LangfuseSpanProcessor({
38
+ publicKey,
39
+ secretKey,
40
+ baseUrl,
41
+ environment: config.environment,
42
+ release: config.release,
43
+ exportMode: this.#realtime ? "immediate" : "batched",
44
+ flushAt: config.flushAt,
45
+ flushInterval: config.flushInterval,
46
+ shouldExportSpan: () => true
47
+ });
48
+ this.#client = new LangfuseClient({
49
+ publicKey,
50
+ secretKey,
51
+ baseUrl
52
+ });
53
+ this.#environment = config.environment ?? process.env.LANGFUSE_TRACING_ENVIRONMENT;
54
+ this.#release = config.release ?? process.env.LANGFUSE_RELEASE;
55
+ }
56
+ init(options) {
57
+ this.#spanConverter = new SpanConverter({
58
+ packageName: "@mastra/langfuse",
59
+ serviceName: options.config?.serviceName,
60
+ format: "GenAI_v1_38_0"
61
+ });
62
+ }
63
+ async _exportTracingEvent(event) {
64
+ if (event.type !== TracingEventType.SPAN_ENDED) return;
65
+ if (!this.#processor) return;
66
+ await this.exportSpan(event.exportedSpan);
67
+ }
68
+ async exportSpan(span) {
69
+ if (!this.#spanConverter) this.#spanConverter = new SpanConverter({
70
+ packageName: "@mastra/langfuse",
71
+ serviceName: "mastra-service",
72
+ format: "GenAI_v1_38_0"
73
+ });
74
+ try {
75
+ const otelSpan = await this.#spanConverter.convertSpan(span);
76
+ mapMastraToLangfuseAttributes(otelSpan.attributes, span, this.#environment, this.#release);
77
+ this.#processor.onEnd(otelSpan);
78
+ } catch (error) {
79
+ this.logger.error(`${LOG_PREFIX} Failed to export span ${span.id}:`, error);
80
+ }
81
+ }
82
+ /**
83
+ * The LangfuseClient instance for advanced Langfuse features.
84
+ * Use this for prompt management, evaluations, datasets, and direct API access.
85
+ */
86
+ get client() {
87
+ return this.#client;
88
+ }
89
+ /**
90
+ * Submit a score to Langfuse. Used by both the new `onScoreEvent` path and the
91
+ * deprecated `addScoreToTrace` wrapper.
92
+ */
93
+ submitScore(args) {
94
+ if (!this.#client) return;
95
+ const { id, traceId, spanId, name, value, comment, metadata } = args;
96
+ try {
97
+ this.#client.score.create({
98
+ id,
99
+ traceId,
100
+ ...spanId ? { observationId: spanId } : {},
101
+ name,
102
+ value,
103
+ ...comment ? { comment } : {},
104
+ ...metadata ? { metadata } : {},
105
+ dataType: "NUMERIC"
106
+ });
107
+ } catch (error) {
108
+ this.logger.error(`${LOG_PREFIX} Error submitting score`, {
109
+ error,
110
+ traceId,
111
+ spanId,
112
+ name
113
+ });
114
+ }
115
+ }
116
+ async onScoreEvent(event) {
117
+ const { score } = event;
118
+ if (!score.traceId) return;
119
+ this.submitScore({
120
+ id: score.scoreId,
121
+ traceId: score.traceId,
122
+ spanId: score.spanId,
123
+ name: score.scorerName ?? score.scorerId,
124
+ value: score.score,
125
+ comment: score.reason,
126
+ metadata: score.metadata
127
+ });
128
+ }
129
+ /**
130
+ * @deprecated Use the observability score event pipeline (`mastra.observability.addScore`)
131
+ * instead. This method is preserved for backwards compatibility and forwards to the same
132
+ * underlying client call as `onScoreEvent`.
133
+ */
134
+ async addScoreToTrace({ traceId, spanId, score, reason, scorerName, metadata }) {
135
+ this.submitScore({
136
+ id: `${traceId}-${spanId || ""}-${scorerName}`,
137
+ traceId,
138
+ spanId,
139
+ name: scorerName,
140
+ value: score,
141
+ comment: reason,
142
+ metadata
143
+ });
144
+ }
145
+ async flush() {
146
+ await Promise.all([this.#processor?.forceFlush(), this.#client?.flush()]);
147
+ }
148
+ async shutdown() {
149
+ await Promise.all([this.#processor?.shutdown(), this.#client?.shutdown()]);
150
+ }
157
151
  };
152
+ /**
153
+ * Maps Mastra-specific OTel attributes to the langfuse.* namespace that
154
+ * Langfuse's OTLP endpoint reads for prompt linking, TTFT, and other features.
155
+ *
156
+ * SpanConverter produces attributes like mastra.metadata.*, mastra.completion_start_time, etc.
157
+ * Langfuse's OTLP server only reads langfuse.observation.prompt.name, langfuse.observation.completion_start_time, etc.
158
+ *
159
+ * This function mutates the attributes object in place.
160
+ * @see https://langfuse.com/integrations/native/opentelemetry#property-mapping
161
+ */
158
162
  function mapMastraToLangfuseAttributes(attributes, span, environment, release) {
159
- if (environment) {
160
- attributes["langfuse.environment"] = environment;
161
- }
162
- if (release) {
163
- attributes["langfuse.release"] = release;
164
- }
165
- const langfuseMetadata = attributes["mastra.metadata.langfuse"];
166
- if (langfuseMetadata) {
167
- try {
168
- const parsed = typeof langfuseMetadata === "string" ? JSON.parse(langfuseMetadata) : langfuseMetadata;
169
- if (parsed && typeof parsed === "object") {
170
- if (parsed.prompt) {
171
- if (parsed.prompt.name !== void 0) {
172
- attributes["langfuse.observation.prompt.name"] = parsed.prompt.name;
173
- }
174
- if (parsed.prompt.version !== void 0) {
175
- attributes["langfuse.observation.prompt.version"] = parsed.prompt.version;
176
- }
177
- }
178
- for (const [key, value] of Object.entries(parsed)) {
179
- if (key === "prompt" || value === null || value === void 0) {
180
- continue;
181
- }
182
- const traceKey = `langfuse.trace.metadata.${key}`;
183
- if (attributes[traceKey] === void 0) {
184
- attributes[traceKey] = typeof value === "string" ? value : JSON.stringify(value);
185
- }
186
- }
187
- }
188
- } catch {
189
- }
190
- delete attributes["mastra.metadata.langfuse"];
191
- }
192
- if (attributes["mastra.completion_start_time"]) {
193
- attributes["langfuse.observation.completion_start_time"] = attributes["mastra.completion_start_time"];
194
- delete attributes["mastra.completion_start_time"];
195
- }
196
- if (attributes["mastra.metadata.userId"]) {
197
- attributes["user.id"] = attributes["mastra.metadata.userId"];
198
- delete attributes["mastra.metadata.userId"];
199
- }
200
- const sessionId = attributes["mastra.metadata.sessionId"] ?? attributes["mastra.metadata.threadId"];
201
- if (sessionId) {
202
- attributes["session.id"] = sessionId;
203
- delete attributes["mastra.metadata.sessionId"];
204
- delete attributes["mastra.metadata.threadId"];
205
- }
206
- if (attributes["mastra.tags"]) {
207
- attributes["langfuse.trace.tags"] = attributes["mastra.tags"];
208
- delete attributes["mastra.tags"];
209
- }
210
- if (attributes["mastra.metadata.traceName"]) {
211
- attributes["langfuse.trace.name"] = attributes["mastra.metadata.traceName"];
212
- delete attributes["mastra.metadata.traceName"];
213
- }
214
- if (attributes["mastra.metadata.version"]) {
215
- attributes["langfuse.trace.version"] = attributes["mastra.metadata.version"];
216
- delete attributes["mastra.metadata.version"];
217
- }
218
- if (span.isRootSpan) {
219
- if (span.type === SpanType.AGENT_RUN) {
220
- if (!attributes["langfuse.trace.name"] && (span.entityName || span.entityId)) {
221
- attributes["langfuse.trace.name"] = span.entityName ?? span.entityId;
222
- }
223
- if (span.entityId) {
224
- attributes["langfuse.trace.metadata.agentId"] = span.entityId;
225
- }
226
- if (span.entityName) {
227
- attributes["langfuse.trace.metadata.agentName"] = span.entityName;
228
- }
229
- } else if (span.type === SpanType.WORKFLOW_RUN) {
230
- if (!attributes["langfuse.trace.name"] && (span.entityName || span.entityId)) {
231
- attributes["langfuse.trace.name"] = span.entityName ?? span.entityId;
232
- }
233
- if (span.entityId) {
234
- attributes["langfuse.trace.metadata.workflowId"] = span.entityId;
235
- }
236
- if (span.entityName) {
237
- attributes["langfuse.trace.metadata.workflowName"] = span.entityName;
238
- }
239
- }
240
- }
241
- if (attributes["gen_ai.agent.id"]) {
242
- attributes["langfuse.observation.metadata.agentId"] = attributes["gen_ai.agent.id"];
243
- }
244
- if (attributes["gen_ai.agent.name"]) {
245
- attributes["langfuse.observation.metadata.agentName"] = attributes["gen_ai.agent.name"];
246
- }
247
- if (attributes["mastra.span.type"]) {
248
- attributes["langfuse.observation.metadata.spanType"] = attributes["mastra.span.type"];
249
- }
250
- if (attributes["gen_ai.operation.name"]) {
251
- attributes["langfuse.observation.metadata.operationName"] = attributes["gen_ai.operation.name"];
252
- }
253
- if (!attributes["gen_ai.input.messages"] && !attributes["gen_ai.tool.call.arguments"]) {
254
- for (const key of Object.keys(attributes)) {
255
- if (key.startsWith("mastra.") && key.endsWith(".input")) {
256
- attributes["langfuse.observation.input"] = attributes[key];
257
- break;
258
- }
259
- }
260
- }
261
- if (!attributes["gen_ai.output.messages"] && !attributes["gen_ai.tool.call.result"]) {
262
- for (const key of Object.keys(attributes)) {
263
- if (key.startsWith("mastra.") && key.endsWith(".output")) {
264
- attributes["langfuse.observation.output"] = attributes[key];
265
- break;
266
- }
267
- }
268
- }
163
+ if (environment) attributes["langfuse.environment"] = environment;
164
+ if (release) attributes["langfuse.release"] = release;
165
+ const langfuseMetadata = attributes["mastra.metadata.langfuse"];
166
+ if (langfuseMetadata) {
167
+ try {
168
+ const parsed = typeof langfuseMetadata === "string" ? JSON.parse(langfuseMetadata) : langfuseMetadata;
169
+ if (parsed && typeof parsed === "object") {
170
+ if (parsed.prompt) {
171
+ if (parsed.prompt.name !== void 0) attributes["langfuse.observation.prompt.name"] = parsed.prompt.name;
172
+ if (parsed.prompt.version !== void 0) attributes["langfuse.observation.prompt.version"] = parsed.prompt.version;
173
+ }
174
+ for (const [key, value] of Object.entries(parsed)) {
175
+ if (key === "prompt" || value === null || value === void 0) continue;
176
+ const traceKey = `langfuse.trace.metadata.${key}`;
177
+ if (attributes[traceKey] === void 0) attributes[traceKey] = typeof value === "string" ? value : JSON.stringify(value);
178
+ }
179
+ }
180
+ } catch {}
181
+ delete attributes["mastra.metadata.langfuse"];
182
+ }
183
+ if (attributes["mastra.completion_start_time"]) {
184
+ attributes["langfuse.observation.completion_start_time"] = attributes["mastra.completion_start_time"];
185
+ delete attributes["mastra.completion_start_time"];
186
+ }
187
+ if (attributes["mastra.metadata.userId"]) {
188
+ attributes["user.id"] = attributes["mastra.metadata.userId"];
189
+ delete attributes["mastra.metadata.userId"];
190
+ }
191
+ const sessionId = attributes["mastra.metadata.sessionId"] ?? attributes["mastra.metadata.threadId"];
192
+ if (sessionId) {
193
+ attributes["session.id"] = sessionId;
194
+ delete attributes["mastra.metadata.sessionId"];
195
+ delete attributes["mastra.metadata.threadId"];
196
+ }
197
+ if (attributes["mastra.tags"]) {
198
+ attributes["langfuse.trace.tags"] = attributes["mastra.tags"];
199
+ delete attributes["mastra.tags"];
200
+ }
201
+ if (attributes["mastra.metadata.traceName"]) {
202
+ attributes["langfuse.trace.name"] = attributes["mastra.metadata.traceName"];
203
+ delete attributes["mastra.metadata.traceName"];
204
+ }
205
+ if (attributes["mastra.metadata.version"]) {
206
+ attributes["langfuse.trace.version"] = attributes["mastra.metadata.version"];
207
+ delete attributes["mastra.metadata.version"];
208
+ }
209
+ if (span.isRootSpan) {
210
+ if (span.type === SpanType.AGENT_RUN) {
211
+ if (!attributes["langfuse.trace.name"] && (span.entityName || span.entityId)) attributes["langfuse.trace.name"] = span.entityName ?? span.entityId;
212
+ if (span.entityId) attributes["langfuse.trace.metadata.agentId"] = span.entityId;
213
+ if (span.entityName) attributes["langfuse.trace.metadata.agentName"] = span.entityName;
214
+ } else if (span.type === SpanType.WORKFLOW_RUN) {
215
+ if (!attributes["langfuse.trace.name"] && (span.entityName || span.entityId)) attributes["langfuse.trace.name"] = span.entityName ?? span.entityId;
216
+ if (span.entityId) attributes["langfuse.trace.metadata.workflowId"] = span.entityId;
217
+ if (span.entityName) attributes["langfuse.trace.metadata.workflowName"] = span.entityName;
218
+ }
219
+ }
220
+ if (attributes["gen_ai.agent.id"]) attributes["langfuse.observation.metadata.agentId"] = attributes["gen_ai.agent.id"];
221
+ if (attributes["gen_ai.agent.name"]) attributes["langfuse.observation.metadata.agentName"] = attributes["gen_ai.agent.name"];
222
+ if (attributes["mastra.span.type"]) attributes["langfuse.observation.metadata.spanType"] = attributes["mastra.span.type"];
223
+ if (attributes["gen_ai.operation.name"]) attributes["langfuse.observation.metadata.operationName"] = attributes["gen_ai.operation.name"];
224
+ if (!attributes["gen_ai.input.messages"] && !attributes["gen_ai.tool.call.arguments"]) {
225
+ for (const key of Object.keys(attributes)) if (key.startsWith("mastra.") && key.endsWith(".input")) {
226
+ attributes["langfuse.observation.input"] = attributes[key];
227
+ break;
228
+ }
229
+ }
230
+ if (!attributes["gen_ai.output.messages"] && !attributes["gen_ai.tool.call.result"]) {
231
+ for (const key of Object.keys(attributes)) if (key.startsWith("mastra.") && key.endsWith(".output")) {
232
+ attributes["langfuse.observation.output"] = attributes[key];
233
+ break;
234
+ }
235
+ }
269
236
  }
237
+ /**
238
+ * Remove trailing "/" characters procedurally. Avoids polynomial
239
+ * backtracking that a greedy regex like `/\/+$/` can exhibit when the
240
+ * input is attacker-controlled.
241
+ */
270
242
  function stripTrailingSlashes(s) {
271
- let end = s.length;
272
- while (end > 0 && s.charCodeAt(end - 1) === 47) {
273
- end--;
274
- }
275
- return end === s.length ? s : s.slice(0, end);
243
+ let end = s.length;
244
+ while (end > 0 && s.charCodeAt(end - 1) === 47) end--;
245
+ return end === s.length ? s : s.slice(0, end);
276
246
  }
277
-
278
- // src/helpers.ts
247
+ //#endregion
248
+ //#region src/helpers.ts
249
+ /**
250
+ * Adds Langfuse prompt metadata to the tracing options
251
+ * to enable Langfuse Prompt Tracing.
252
+ *
253
+ * The metadata is added under `metadata.langfuse.prompt` and includes:
254
+ * - `name` - Prompt name (required for Langfuse v5)
255
+ * - `version` - Prompt version (required for Langfuse v5)
256
+ *
257
+ * All fields are deeply merged with any existing metadata.
258
+ *
259
+ * @param prompt - Prompt fields for linking (`name` and `version` required)
260
+ * @returns A TracingOptionsUpdater function for use with `buildTracingOptions`
261
+ *
262
+ * @example
263
+ * ```typescript
264
+ * import { buildTracingOptions } from '@mastra/observability';
265
+ * import { withLangfusePrompt } from '@mastra/langfuse';
266
+ *
267
+ * // Link a generation to a Langfuse prompt by name and version
268
+ * const tracingOptions = buildTracingOptions(
269
+ * withLangfusePrompt({ name: 'customer-support', version: 1 }),
270
+ * );
271
+ *
272
+ * // Or directly in agent config
273
+ * const agent = new Agent({
274
+ * name: 'support-agent',
275
+ * instructions: 'You are a helpful assistant',
276
+ * model: openai('gpt-4o'),
277
+ * defaultGenerateOptions: {
278
+ * tracingOptions: buildTracingOptions(
279
+ * withLangfusePrompt({ name: 'my-prompt', version: 1 }),
280
+ * ),
281
+ * },
282
+ * });
283
+ * ```
284
+ */
279
285
  function withLangfusePrompt(prompt) {
280
- return (opts) => ({
281
- ...opts,
282
- metadata: {
283
- ...opts.metadata,
284
- langfuse: {
285
- ...opts.metadata?.langfuse,
286
- prompt: {
287
- ...prompt.name !== void 0 && { name: prompt.name },
288
- ...prompt.version !== void 0 && { version: prompt.version },
289
- ...prompt.id !== void 0 && { id: prompt.id }
290
- }
291
- }
292
- }
293
- });
286
+ return (opts) => ({
287
+ ...opts,
288
+ metadata: {
289
+ ...opts.metadata,
290
+ langfuse: {
291
+ ...opts.metadata?.langfuse,
292
+ prompt: {
293
+ ...prompt.name !== void 0 && { name: prompt.name },
294
+ ...prompt.version !== void 0 && { version: prompt.version },
295
+ ...prompt.id !== void 0 && { id: prompt.id }
296
+ }
297
+ }
298
+ }
299
+ });
294
300
  }
295
-
301
+ //#endregion
296
302
  export { LANGFUSE_DEFAULT_BASE_URL, LangfuseExporter, withLangfusePrompt };
297
- //# sourceMappingURL=index.js.map
303
+
298
304
  //# sourceMappingURL=index.js.map