@mastra/langfuse 1.0.12-alpha.0 → 1.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/dist/helpers.d.ts +13 -21
- package/dist/helpers.d.ts.map +1 -1
- package/dist/index.cjs +125 -217
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +127 -220
- package/dist/index.js.map +1 -1
- package/dist/tracing.d.ts +28 -70
- package/dist/tracing.d.ts.map +1 -1
- package/package.json +14 -9
- package/dist/metrics.d.ts +0 -17
- package/dist/metrics.d.ts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @mastra/langfuse
|
|
2
2
|
|
|
3
|
+
## 1.1.0-alpha.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Upgraded Langfuse integration to the official v5 SDK, replacing the deprecated v3 package. ([#14985](https://github.com/mastra-ai/mastra/pull/14985))
|
|
8
|
+
|
|
9
|
+
**New features:**
|
|
10
|
+
- Access Langfuse's full platform via `exporter.client` — prompt management, datasets, evaluations, and scoring
|
|
11
|
+
- New `environment` and `release` config options for filtering traces in the Langfuse dashboard
|
|
12
|
+
|
|
13
|
+
**No breaking changes to your existing code** — `LangfuseExporter`, `LangfuseExporterConfig`, and `withLangfusePrompt()` work the same way. Just upgrade the package and your traces will use the latest Langfuse format.
|
|
14
|
+
|
|
15
|
+
**Note:** `withLangfusePrompt({ id })` is deprecated — Langfuse v5 requires `name` + `version` for prompt linking.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies [[`ac7baf6`](https://github.com/mastra-ai/mastra/commit/ac7baf66ef1db15e03975ef4ebb02724f015a391), [`0df8321`](https://github.com/mastra-ai/mastra/commit/0df832196eeb2450ab77ce887e8553abdd44c5a6), [`deb0888`](https://github.com/mastra-ai/mastra/commit/deb08881cd35468421dfb30bf5e2ec21cd1ca4e1), [`d26ad28`](https://github.com/mastra-ai/mastra/commit/d26ad2899edd83b9c4dceb8a8a428e64b8775aef), [`61109b3`](https://github.com/mastra-ai/mastra/commit/61109b34feb0e38d54bee4b8ca83eb7345b1d557), [`33f1ead`](https://github.com/mastra-ai/mastra/commit/33f1eadfa19c86953f593478e5fa371093b33779)]:
|
|
20
|
+
- @mastra/core@1.23.0-alpha.8
|
|
21
|
+
- @mastra/otel-exporter@1.0.13-alpha.0
|
|
22
|
+
- @mastra/observability@1.7.3-alpha.0
|
|
23
|
+
|
|
24
|
+
## 1.0.12
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- Updated dependencies [[`cb15509`](https://github.com/mastra-ai/mastra/commit/cb15509b58f6a83e11b765c945082afc027db972), [`81e4259`](https://github.com/mastra-ai/mastra/commit/81e425939b4ceeb4f586e9b6d89c3b1c1f2d2fe7), [`951b8a1`](https://github.com/mastra-ai/mastra/commit/951b8a1b5ef7e1474c59dc4f2b9fc1a8b1e508b6), [`80c5668`](https://github.com/mastra-ai/mastra/commit/80c5668e365470d3a96d3e953868fd7a643ff67c), [`951b8a1`](https://github.com/mastra-ai/mastra/commit/951b8a1b5ef7e1474c59dc4f2b9fc1a8b1e508b6), [`3d478c1`](https://github.com/mastra-ai/mastra/commit/3d478c1e13f17b80f330ac49d7aa42ef929b93ff), [`2b4ea10`](https://github.com/mastra-ai/mastra/commit/2b4ea10b053e4ea1ab232d536933a4a3c4cba999), [`a0544f0`](https://github.com/mastra-ai/mastra/commit/a0544f0a1e6bd52ac12676228967c1938e43648d), [`6039f17`](https://github.com/mastra-ai/mastra/commit/6039f176f9c457304825ff1df8c83b8e457376c0), [`06b928d`](https://github.com/mastra-ai/mastra/commit/06b928dfc2f5630d023467476cc5919dfa858d0a), [`6a8d984`](https://github.com/mastra-ai/mastra/commit/6a8d9841f2933456ee1598099f488d742b600054), [`c8c86aa`](https://github.com/mastra-ai/mastra/commit/c8c86aa1458017fbd1c0776fdc0c520d129df8a6)]:
|
|
29
|
+
- @mastra/core@1.22.0
|
|
30
|
+
- @mastra/observability@1.7.2
|
|
31
|
+
|
|
3
32
|
## 1.0.12-alpha.0
|
|
4
33
|
|
|
5
34
|
### Patch Changes
|
package/dist/helpers.d.ts
CHANGED
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
* import { buildTracingOptions } from '@mastra/observability';
|
|
10
10
|
* import { withLangfusePrompt } from '@mastra/langfuse';
|
|
11
11
|
*
|
|
12
|
-
* const prompt = await langfuse.getPrompt('my-prompt');
|
|
13
|
-
*
|
|
14
12
|
* const agent = new Agent({
|
|
15
13
|
* defaultGenerateOptions: {
|
|
16
|
-
* tracingOptions: buildTracingOptions(
|
|
14
|
+
* tracingOptions: buildTracingOptions(
|
|
15
|
+
* withLangfusePrompt({ name: 'my-prompt', version: 1 }),
|
|
16
|
+
* ),
|
|
17
17
|
* },
|
|
18
18
|
* });
|
|
19
19
|
* ```
|
|
@@ -28,7 +28,7 @@ export interface LangfusePromptInput {
|
|
|
28
28
|
name?: string;
|
|
29
29
|
/** Prompt version */
|
|
30
30
|
version?: number;
|
|
31
|
-
/**
|
|
31
|
+
/** @deprecated Langfuse v5 only supports linking by name + version. This field is ignored. */
|
|
32
32
|
id?: string;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
@@ -36,43 +36,35 @@ export interface LangfusePromptInput {
|
|
|
36
36
|
* to enable Langfuse Prompt Tracing.
|
|
37
37
|
*
|
|
38
38
|
* The metadata is added under `metadata.langfuse.prompt` and includes:
|
|
39
|
-
* - `name` - Prompt name
|
|
40
|
-
* - `version` - Prompt version
|
|
41
|
-
* - `id` - Prompt UUID
|
|
39
|
+
* - `name` - Prompt name (required for Langfuse v5)
|
|
40
|
+
* - `version` - Prompt version (required for Langfuse v5)
|
|
42
41
|
*
|
|
43
42
|
* All fields are deeply merged with any existing metadata.
|
|
44
43
|
*
|
|
45
|
-
* @param prompt -
|
|
44
|
+
* @param prompt - Prompt fields for linking (`name` and `version` required)
|
|
46
45
|
* @returns A TracingOptionsUpdater function for use with `buildTracingOptions`
|
|
47
46
|
*
|
|
48
47
|
* @example
|
|
49
48
|
* ```typescript
|
|
50
49
|
* import { buildTracingOptions } from '@mastra/observability';
|
|
51
50
|
* 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
51
|
*
|
|
57
|
-
* //
|
|
52
|
+
* // Link a generation to a Langfuse prompt by name and version
|
|
58
53
|
* const tracingOptions = buildTracingOptions(
|
|
59
|
-
* withLangfusePrompt(
|
|
54
|
+
* withLangfusePrompt({ name: 'customer-support', version: 1 }),
|
|
60
55
|
* );
|
|
61
56
|
*
|
|
62
57
|
* // Or directly in agent config
|
|
63
58
|
* const agent = new Agent({
|
|
64
59
|
* name: 'support-agent',
|
|
65
|
-
* instructions:
|
|
60
|
+
* instructions: 'You are a helpful assistant',
|
|
66
61
|
* model: openai('gpt-4o'),
|
|
67
62
|
* defaultGenerateOptions: {
|
|
68
|
-
* tracingOptions: buildTracingOptions(
|
|
63
|
+
* tracingOptions: buildTracingOptions(
|
|
64
|
+
* withLangfusePrompt({ name: 'my-prompt', version: 1 }),
|
|
65
|
+
* ),
|
|
69
66
|
* },
|
|
70
67
|
* });
|
|
71
|
-
*
|
|
72
|
-
* // Manual fields also work
|
|
73
|
-
* const tracingOptions = buildTracingOptions(
|
|
74
|
-
* withLangfusePrompt({ name: 'my-prompt', version: 1 }),
|
|
75
|
-
* );
|
|
76
68
|
* ```
|
|
77
69
|
*/
|
|
78
70
|
export declare function withLangfusePrompt(prompt: LangfusePromptInput): TracingOptionsUpdater;
|
package/dist/helpers.d.ts.map
CHANGED
|
@@ -1 +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,
|
|
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,8FAA8F;IAC9F,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,qBAAqB,CAerF"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,237 +1,93 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var client = require('@langfuse/client');
|
|
4
|
+
var otel = require('@langfuse/otel');
|
|
3
5
|
var observability$1 = require('@mastra/core/observability');
|
|
4
|
-
var utils = require('@mastra/core/utils');
|
|
5
6
|
var observability = require('@mastra/observability');
|
|
6
|
-
var
|
|
7
|
+
var otelExporter = require('@mastra/otel-exporter');
|
|
7
8
|
|
|
8
9
|
// src/tracing.ts
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (!usage) return {};
|
|
13
|
-
const metrics = {};
|
|
14
|
-
if (usage.inputTokens !== void 0) {
|
|
15
|
-
metrics.input = usage.inputTokens;
|
|
16
|
-
if (usage.inputDetails?.cacheRead !== void 0) {
|
|
17
|
-
metrics.cache_read_input_tokens = usage.inputDetails.cacheRead;
|
|
18
|
-
metrics.input -= metrics.cache_read_input_tokens;
|
|
19
|
-
}
|
|
20
|
-
if (usage.inputDetails?.cacheWrite !== void 0) {
|
|
21
|
-
metrics.cache_write_input_tokens = usage.inputDetails.cacheWrite;
|
|
22
|
-
metrics.input -= metrics.cache_write_input_tokens;
|
|
23
|
-
}
|
|
24
|
-
if (metrics.input < 0) metrics.input = 0;
|
|
25
|
-
}
|
|
26
|
-
if (usage.outputTokens !== void 0) {
|
|
27
|
-
metrics.output = usage.outputTokens;
|
|
28
|
-
}
|
|
29
|
-
if (usage.outputDetails?.reasoning !== void 0) {
|
|
30
|
-
metrics.reasoning = usage.outputDetails.reasoning;
|
|
31
|
-
}
|
|
32
|
-
if (metrics.input != null && metrics.output != null) {
|
|
33
|
-
metrics.total = metrics.input + metrics.output;
|
|
34
|
-
if (metrics.cache_read_input_tokens != null) {
|
|
35
|
-
metrics.total += metrics.cache_read_input_tokens;
|
|
36
|
-
}
|
|
37
|
-
if (metrics.cache_write_input_tokens != null) {
|
|
38
|
-
metrics.total += metrics.cache_write_input_tokens;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return metrics;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// src/tracing.ts
|
|
45
|
-
var LangfuseExporter = class extends observability.TrackingExporter {
|
|
10
|
+
var LOG_PREFIX = "[LangfuseExporter]";
|
|
11
|
+
var LANGFUSE_DEFAULT_BASE_URL = "https://cloud.langfuse.com";
|
|
12
|
+
var LangfuseExporter = class extends observability.BaseExporter {
|
|
46
13
|
name = "langfuse";
|
|
14
|
+
#processor;
|
|
47
15
|
#client;
|
|
16
|
+
#spanConverter;
|
|
48
17
|
#realtime;
|
|
18
|
+
#environment;
|
|
19
|
+
#release;
|
|
49
20
|
constructor(config = {}) {
|
|
21
|
+
super(config);
|
|
50
22
|
const publicKey = config.publicKey ?? process.env.LANGFUSE_PUBLIC_KEY;
|
|
51
23
|
const secretKey = config.secretKey ?? process.env.LANGFUSE_SECRET_KEY;
|
|
52
|
-
const baseUrl = config.baseUrl ?? process.env.LANGFUSE_BASE_URL;
|
|
53
|
-
super({
|
|
54
|
-
...config,
|
|
55
|
-
publicKey,
|
|
56
|
-
secretKey,
|
|
57
|
-
baseUrl
|
|
58
|
-
});
|
|
24
|
+
const baseUrl = (config.baseUrl ?? process.env.LANGFUSE_BASE_URL ?? LANGFUSE_DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
59
25
|
this.#realtime = config.realtime ?? false;
|
|
60
26
|
if (!publicKey || !secretKey) {
|
|
61
27
|
const publicKeySource = config.publicKey ? "from config" : process.env.LANGFUSE_PUBLIC_KEY ? "from env" : "missing";
|
|
62
28
|
const secretKeySource = config.secretKey ? "from config" : process.env.LANGFUSE_SECRET_KEY ? "from env" : "missing";
|
|
63
29
|
this.setDisabled(
|
|
64
|
-
|
|
30
|
+
`${LOG_PREFIX} Missing required credentials (publicKey: ${publicKeySource}, secretKey: ${secretKeySource}). Set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY environment variables or pass them in config.`
|
|
65
31
|
);
|
|
66
32
|
return;
|
|
67
33
|
}
|
|
68
|
-
this.#
|
|
34
|
+
this.#processor = new otel.LangfuseSpanProcessor({
|
|
69
35
|
publicKey,
|
|
70
36
|
secretKey,
|
|
71
37
|
baseUrl,
|
|
72
|
-
|
|
38
|
+
environment: config.environment,
|
|
39
|
+
release: config.release,
|
|
40
|
+
exportMode: this.#realtime ? "immediate" : "batched",
|
|
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
|
|
73
44
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (!langfuseParent) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
const payload = this.buildSpanPayload(span, true, traceData);
|
|
91
|
-
return langfuseParent.event(payload);
|
|
92
|
-
}
|
|
93
|
-
async _buildSpan(args) {
|
|
94
|
-
const { span, traceData } = args;
|
|
95
|
-
const langfuseParent = traceData.getParentOrRoot({ span });
|
|
96
|
-
if (!langfuseParent) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
const payload = this.buildSpanPayload(span, true, traceData);
|
|
100
|
-
const langfuseSpan = span.type === observability$1.SpanType.MODEL_GENERATION ? langfuseParent.generation(payload) : langfuseParent.span(payload);
|
|
101
|
-
this.logger.debug(`${this.name}: built span`, {
|
|
102
|
-
traceId: span.traceId,
|
|
103
|
-
spanId: payload.id,
|
|
104
|
-
method: "_buildSpan"
|
|
45
|
+
this.#client = new client.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 otelExporter.SpanConverter({
|
|
55
|
+
packageName: "@mastra/langfuse",
|
|
56
|
+
serviceName: options.config?.serviceName,
|
|
57
|
+
format: "GenAI_v1_38_0"
|
|
105
58
|
});
|
|
106
|
-
return langfuseSpan;
|
|
107
59
|
}
|
|
108
|
-
async
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
60
|
+
async _exportTracingEvent(event) {
|
|
61
|
+
if (event.type !== observability$1.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 otelExporter.SpanConverter({
|
|
68
|
+
packageName: "@mastra/langfuse",
|
|
69
|
+
serviceName: "mastra-service",
|
|
70
|
+
format: "GenAI_v1_38_0"
|
|
116
71
|
});
|
|
117
|
-
const updatePayload = this.buildSpanPayload(span, false, traceData);
|
|
118
|
-
langfuseSpan.update(updatePayload);
|
|
119
72
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const langfuseRoot = traceData.getRoot();
|
|
127
|
-
langfuseRoot?.update({ output: span.output });
|
|
73
|
+
try {
|
|
74
|
+
const otelSpan = await this.#spanConverter.convertSpan(span);
|
|
75
|
+
mapMastraToLangfuseAttributes(otelSpan.attributes, 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);
|
|
128
79
|
}
|
|
129
80
|
}
|
|
130
|
-
async _abortSpan(args) {
|
|
131
|
-
const { span, reason } = args;
|
|
132
|
-
span.end({
|
|
133
|
-
level: "ERROR",
|
|
134
|
-
statusMessage: reason.message
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
buildTracePayload(span) {
|
|
138
|
-
const payload = {
|
|
139
|
-
id: span.traceId,
|
|
140
|
-
name: span.name
|
|
141
|
-
};
|
|
142
|
-
const { userId, sessionId, ...remainingMetadata } = span.metadata ?? {};
|
|
143
|
-
if (userId) payload.userId = userId;
|
|
144
|
-
if (sessionId) payload.sessionId = sessionId;
|
|
145
|
-
if (span.input) payload.input = span.input;
|
|
146
|
-
if (span.tags?.length) payload.tags = span.tags;
|
|
147
|
-
payload.metadata = {
|
|
148
|
-
spanType: span.type,
|
|
149
|
-
...span.attributes,
|
|
150
|
-
...remainingMetadata
|
|
151
|
-
};
|
|
152
|
-
return payload;
|
|
153
|
-
}
|
|
154
81
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* is set on a parent span (e.g., AGENT_RUN) rather than directly on the generation.
|
|
158
|
-
* This enables prompt linking when:
|
|
159
|
-
* - A workflow calls multiple agents, each with different prompts
|
|
160
|
-
* - Nested agents have different prompts
|
|
161
|
-
* - The prompt is set on AGENT_RUN but MODEL_GENERATION inherits it
|
|
82
|
+
* The LangfuseClient instance for advanced Langfuse features.
|
|
83
|
+
* Use this for prompt management, evaluations, datasets, and direct API access.
|
|
162
84
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
while (currentSpanId) {
|
|
166
|
-
const providerMetadata = traceData.getMetadata({ spanId: currentSpanId });
|
|
167
|
-
if (providerMetadata?.prompt) {
|
|
168
|
-
this.logger.debug(`${this.name}: found prompt in provider metadata`, {
|
|
169
|
-
traceId: span.traceId,
|
|
170
|
-
spanId: span.id,
|
|
171
|
-
prompt: providerMetadata?.prompt
|
|
172
|
-
});
|
|
173
|
-
return providerMetadata.prompt;
|
|
174
|
-
}
|
|
175
|
-
currentSpanId = traceData.getParentId({ spanId: currentSpanId });
|
|
176
|
-
}
|
|
177
|
-
return void 0;
|
|
178
|
-
}
|
|
179
|
-
buildSpanPayload(span, isCreate, traceData) {
|
|
180
|
-
const payload = {};
|
|
181
|
-
if (isCreate) {
|
|
182
|
-
payload.id = span.id;
|
|
183
|
-
payload.name = span.name;
|
|
184
|
-
payload.startTime = span.startTime;
|
|
185
|
-
}
|
|
186
|
-
if (span.input !== void 0) payload.input = span.input;
|
|
187
|
-
if (span.output !== void 0) payload.output = span.output;
|
|
188
|
-
if (span.endTime !== void 0) payload.endTime = span.endTime;
|
|
189
|
-
const attributes = span.attributes ?? {};
|
|
190
|
-
const metadata = {
|
|
191
|
-
...span.metadata
|
|
192
|
-
};
|
|
193
|
-
const attributesToOmit = [];
|
|
194
|
-
const metadataToOmit = [];
|
|
195
|
-
if (span.type === observability$1.SpanType.MODEL_GENERATION) {
|
|
196
|
-
const modelAttr = attributes;
|
|
197
|
-
if (modelAttr.model !== void 0) {
|
|
198
|
-
payload.model = modelAttr.model;
|
|
199
|
-
attributesToOmit.push("model");
|
|
200
|
-
}
|
|
201
|
-
if (modelAttr.usage !== void 0) {
|
|
202
|
-
payload.usageDetails = formatUsageMetrics(modelAttr.usage);
|
|
203
|
-
attributesToOmit.push("usage");
|
|
204
|
-
}
|
|
205
|
-
if (modelAttr.parameters !== void 0) {
|
|
206
|
-
payload.modelParameters = modelAttr.parameters;
|
|
207
|
-
attributesToOmit.push("parameters");
|
|
208
|
-
}
|
|
209
|
-
const promptData = this.findLangfusePrompt(traceData, span);
|
|
210
|
-
const hasNameAndVersion = promptData?.name !== void 0 && promptData?.version !== void 0;
|
|
211
|
-
const hasId = promptData?.id !== void 0;
|
|
212
|
-
if (hasNameAndVersion || hasId) {
|
|
213
|
-
payload.prompt = {};
|
|
214
|
-
if (promptData?.name !== void 0) payload.prompt.name = promptData.name;
|
|
215
|
-
if (promptData?.version !== void 0) payload.prompt.version = promptData.version;
|
|
216
|
-
if (promptData?.id !== void 0) payload.prompt.id = promptData.id;
|
|
217
|
-
metadataToOmit.push("langfuse");
|
|
218
|
-
}
|
|
219
|
-
if (modelAttr.completionStartTime !== void 0) {
|
|
220
|
-
payload.completionStartTime = modelAttr.completionStartTime;
|
|
221
|
-
attributesToOmit.push("completionStartTime");
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
payload.metadata = {
|
|
225
|
-
spanType: span.type,
|
|
226
|
-
...utils.omitKeys(attributes, attributesToOmit),
|
|
227
|
-
...utils.omitKeys(metadata, metadataToOmit)
|
|
228
|
-
};
|
|
229
|
-
if (span.errorInfo) {
|
|
230
|
-
payload.level = "ERROR";
|
|
231
|
-
payload.statusMessage = span.errorInfo.message;
|
|
232
|
-
}
|
|
233
|
-
return payload;
|
|
85
|
+
get client() {
|
|
86
|
+
return this.#client;
|
|
234
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Add a score to a trace via the Langfuse client.
|
|
90
|
+
*/
|
|
235
91
|
async addScoreToTrace({
|
|
236
92
|
traceId,
|
|
237
93
|
spanId,
|
|
@@ -242,18 +98,18 @@ var LangfuseExporter = class extends observability.TrackingExporter {
|
|
|
242
98
|
}) {
|
|
243
99
|
if (!this.#client) return;
|
|
244
100
|
try {
|
|
245
|
-
|
|
246
|
-
id: `${traceId}-${scorerName}`,
|
|
101
|
+
this.#client.score.create({
|
|
102
|
+
id: `${traceId}-${spanId || ""}-${scorerName}`,
|
|
247
103
|
traceId,
|
|
248
|
-
observationId: spanId,
|
|
104
|
+
...spanId ? { observationId: spanId } : {},
|
|
249
105
|
name: scorerName,
|
|
250
106
|
value: score,
|
|
251
|
-
...
|
|
252
|
-
metadata
|
|
107
|
+
...reason ? { comment: reason } : {},
|
|
108
|
+
...metadata ? { metadata } : {},
|
|
253
109
|
dataType: "NUMERIC"
|
|
254
110
|
});
|
|
255
111
|
} catch (error) {
|
|
256
|
-
this.logger.error(
|
|
112
|
+
this.logger.error(`${LOG_PREFIX} Error adding score to trace`, {
|
|
257
113
|
error,
|
|
258
114
|
traceId,
|
|
259
115
|
spanId,
|
|
@@ -261,20 +117,71 @@ var LangfuseExporter = class extends observability.TrackingExporter {
|
|
|
261
117
|
});
|
|
262
118
|
}
|
|
263
119
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
async
|
|
268
|
-
|
|
269
|
-
|
|
120
|
+
async flush() {
|
|
121
|
+
await Promise.all([this.#processor?.forceFlush(), this.#client?.flush()]);
|
|
122
|
+
}
|
|
123
|
+
async shutdown() {
|
|
124
|
+
await Promise.all([this.#processor?.shutdown(), this.#client?.shutdown()]);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
function mapMastraToLangfuseAttributes(attributes, environment, release) {
|
|
128
|
+
if (environment) {
|
|
129
|
+
attributes["langfuse.environment"] = environment;
|
|
130
|
+
}
|
|
131
|
+
if (release) {
|
|
132
|
+
attributes["langfuse.release"] = release;
|
|
133
|
+
}
|
|
134
|
+
const langfuseMetadata = attributes["mastra.metadata.langfuse"];
|
|
135
|
+
if (langfuseMetadata) {
|
|
136
|
+
try {
|
|
137
|
+
const parsed = typeof langfuseMetadata === "string" ? JSON.parse(langfuseMetadata) : langfuseMetadata;
|
|
138
|
+
if (parsed?.prompt) {
|
|
139
|
+
if (parsed.prompt.name !== void 0) {
|
|
140
|
+
attributes["langfuse.observation.prompt.name"] = parsed.prompt.name;
|
|
141
|
+
}
|
|
142
|
+
if (parsed.prompt.version !== void 0) {
|
|
143
|
+
attributes["langfuse.observation.prompt.version"] = parsed.prompt.version;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} catch {
|
|
270
147
|
}
|
|
148
|
+
delete attributes["mastra.metadata.langfuse"];
|
|
149
|
+
}
|
|
150
|
+
if (attributes["mastra.completion_start_time"]) {
|
|
151
|
+
attributes["langfuse.observation.completion_start_time"] = attributes["mastra.completion_start_time"];
|
|
152
|
+
delete attributes["mastra.completion_start_time"];
|
|
153
|
+
}
|
|
154
|
+
if (attributes["mastra.metadata.userId"]) {
|
|
155
|
+
attributes["user.id"] = attributes["mastra.metadata.userId"];
|
|
156
|
+
delete attributes["mastra.metadata.userId"];
|
|
271
157
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
158
|
+
const sessionId = attributes["mastra.metadata.sessionId"] ?? attributes["mastra.metadata.threadId"];
|
|
159
|
+
if (sessionId) {
|
|
160
|
+
attributes["session.id"] = sessionId;
|
|
161
|
+
delete attributes["mastra.metadata.sessionId"];
|
|
162
|
+
delete attributes["mastra.metadata.threadId"];
|
|
163
|
+
}
|
|
164
|
+
if (attributes["mastra.tags"]) {
|
|
165
|
+
attributes["langfuse.trace.tags"] = attributes["mastra.tags"];
|
|
166
|
+
delete attributes["mastra.tags"];
|
|
167
|
+
}
|
|
168
|
+
if (!attributes["gen_ai.input.messages"] && !attributes["gen_ai.tool.call.arguments"]) {
|
|
169
|
+
for (const key of Object.keys(attributes)) {
|
|
170
|
+
if (key.startsWith("mastra.") && key.endsWith(".input")) {
|
|
171
|
+
attributes["langfuse.observation.input"] = attributes[key];
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
275
174
|
}
|
|
276
175
|
}
|
|
277
|
-
|
|
176
|
+
if (!attributes["gen_ai.output.messages"] && !attributes["gen_ai.tool.call.result"]) {
|
|
177
|
+
for (const key of Object.keys(attributes)) {
|
|
178
|
+
if (key.startsWith("mastra.") && key.endsWith(".output")) {
|
|
179
|
+
attributes["langfuse.observation.output"] = attributes[key];
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
278
185
|
|
|
279
186
|
// src/helpers.ts
|
|
280
187
|
function withLangfusePrompt(prompt) {
|
|
@@ -294,6 +201,7 @@ function withLangfusePrompt(prompt) {
|
|
|
294
201
|
});
|
|
295
202
|
}
|
|
296
203
|
|
|
204
|
+
exports.LANGFUSE_DEFAULT_BASE_URL = LANGFUSE_DEFAULT_BASE_URL;
|
|
297
205
|
exports.LangfuseExporter = LangfuseExporter;
|
|
298
206
|
exports.withLangfusePrompt = withLangfusePrompt;
|
|
299
207
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/metrics.ts","../src/tracing.ts","../src/helpers.ts"],"names":["TrackingExporter","Langfuse","SpanType","omitKeys"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { UsageStats } from '@mastra/core/observability';\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 // Start with total input tokens (which includes cached tokens from usage.ts)\n metrics.input = usage.inputTokens;\n\n // Langfuse expects 'input' to be NON-cached tokens only.\n // Subtract cache tokens to get the actual non-cached input count.\n // See: https://langfuse.com/docs/observability/features/token-and-cost-tracking\n if (usage.inputDetails?.cacheRead !== undefined) {\n metrics.cache_read_input_tokens = usage.inputDetails.cacheRead;\n metrics.input -= metrics.cache_read_input_tokens;\n }\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 // Defensive clamp: ensure input tokens is never negative\n if (metrics.input < 0) metrics.input = 0;\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 // Calculate total: input + cache_read + cache_write + output\n // Use explicit null checks to handle zero values correctly\n if (metrics.input != null && metrics.output != null) {\n metrics.total = metrics.input + metrics.output;\n if (metrics.cache_read_input_tokens != null) {\n metrics.total += metrics.cache_read_input_tokens;\n }\n if (metrics.cache_write_input_tokens != null) {\n metrics.total += metrics.cache_write_input_tokens;\n }\n }\n\n return metrics;\n}\n","/**\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 { AnyExportedSpan, ModelGenerationAttributes, SpanErrorInfo } from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { TrackingExporter } from '@mastra/observability';\nimport type { TrackingExporterConfig, TraceData } from '@mastra/observability';\nimport { Langfuse } from 'langfuse';\nimport type { LangfuseTraceClient, LangfuseSpanClient, LangfuseGenerationClient, LangfuseEventClient } from 'langfuse';\nimport { formatUsageMetrics } from './metrics';\n\nexport interface LangfuseExporterConfig extends TrackingExporterConfig {\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\n/**\n * With Langfuse, data from the root span is stored in both the Root and the\n * first span.\n */\n\ntype LangfuseRoot = LangfuseTraceClient;\ntype LangfuseSpan = LangfuseSpanClient | LangfuseGenerationClient;\ntype LangfuseEvent = LangfuseEventClient;\ntype LangfuseMetadata = { prompt?: LangfusePromptData };\ntype LangfuseTraceData = TraceData<LangfuseRoot, LangfuseSpan, LangfuseEvent, LangfuseMetadata>;\n\nexport class LangfuseExporter extends TrackingExporter<\n LangfuseRoot,\n LangfuseSpan,\n LangfuseEvent,\n LangfuseMetadata,\n LangfuseExporterConfig\n> {\n name = 'langfuse';\n #client: Langfuse | undefined;\n #realtime: boolean;\n\n constructor(config: LangfuseExporterConfig = {}) {\n // Resolve env vars BEFORE calling super (config is readonly in base class)\n const publicKey = config.publicKey ?? process.env.LANGFUSE_PUBLIC_KEY;\n const secretKey = config.secretKey ?? process.env.LANGFUSE_SECRET_KEY;\n const baseUrl = config.baseUrl ?? process.env.LANGFUSE_BASE_URL;\n\n super({\n ...config,\n publicKey,\n secretKey,\n baseUrl,\n });\n\n this.#realtime = config.realtime ?? false;\n\n if (!publicKey || !secretKey) {\n const publicKeySource = config.publicKey\n ? 'from config'\n : process.env.LANGFUSE_PUBLIC_KEY\n ? 'from env'\n : 'missing';\n const secretKeySource = config.secretKey\n ? 'from config'\n : process.env.LANGFUSE_SECRET_KEY\n ? 'from env'\n : 'missing';\n this.setDisabled(\n `Missing required credentials (publicKey: ${publicKeySource}, secretKey: ${secretKeySource}). ` +\n `Set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY environment variables or pass them in config.`,\n );\n return;\n }\n\n this.#client = new Langfuse({\n publicKey,\n secretKey,\n baseUrl,\n ...config.options,\n });\n }\n\n protected override async _postExportTracingEvent(): Promise<void> {\n // Flush immediately in realtime mode for instant visibility\n if (this.#realtime) {\n await this.#client?.flushAsync();\n }\n }\n\n protected override async _buildRoot(args: {\n span: AnyExportedSpan;\n traceData: LangfuseTraceData;\n }): Promise<LangfuseTraceClient | undefined> {\n const { span } = args;\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 return this.#client?.trace(this.buildTracePayload(span));\n }\n\n protected override async _buildEvent(args: {\n span: AnyExportedSpan;\n traceData: LangfuseTraceData;\n }): Promise<LangfuseEvent | undefined> {\n const { span, traceData } = args;\n const langfuseParent = traceData.getParentOrRoot({ span });\n if (!langfuseParent) {\n return;\n }\n\n const payload = this.buildSpanPayload(span, true, traceData);\n return langfuseParent.event(payload);\n }\n\n protected override async _buildSpan(args: {\n span: AnyExportedSpan;\n traceData: LangfuseTraceData;\n }): Promise<LangfuseSpan | undefined> {\n const { span, traceData } = args;\n const langfuseParent = traceData.getParentOrRoot({ span });\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 this.logger.debug(`${this.name}: built span`, {\n traceId: span.traceId,\n spanId: payload.id,\n method: '_buildSpan',\n });\n\n return langfuseSpan;\n }\n\n protected override async _updateSpan(args: { span: AnyExportedSpan; traceData: LangfuseTraceData }): Promise<void> {\n const { span, traceData } = args;\n const langfuseSpan = traceData.getSpan({ spanId: span.id });\n if (langfuseSpan) {\n this.logger.debug(`${this.name}: found span for update`, {\n traceId: span.traceId,\n spanId: langfuseSpan.id,\n method: '_updateSpan',\n });\n\n const updatePayload = this.buildSpanPayload(span, false, traceData);\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(updatePayload);\n }\n }\n\n protected override async _finishSpan(args: { span: AnyExportedSpan; traceData: LangfuseTraceData }): Promise<void> {\n const { span, traceData } = args;\n const langfuseSpan = traceData.getSpan({ spanId: span.id });\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 (span.isRootSpan) {\n const langfuseRoot = traceData.getRoot();\n langfuseRoot?.update({ output: span.output });\n }\n }\n\n protected override async _abortSpan(args: { span: LangfuseSpan; reason: SpanErrorInfo }): Promise<void> {\n const { span, reason } = args;\n span.end({\n level: 'ERROR',\n statusMessage: reason.message,\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 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 * 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 */\n private findLangfusePrompt(traceData: LangfuseTraceData, span: AnyExportedSpan): LangfusePromptData | undefined {\n let currentSpanId: string | undefined = span.id;\n\n while (currentSpanId) {\n const providerMetadata = traceData.getMetadata({ spanId: currentSpanId });\n\n if (providerMetadata?.prompt) {\n this.logger.debug(`${this.name}: found prompt in provider metadata`, {\n traceId: span.traceId,\n spanId: span.id,\n prompt: providerMetadata?.prompt,\n });\n return providerMetadata.prompt;\n }\n currentSpanId = traceData.getParentId({ spanId: currentSpanId });\n }\n\n return undefined;\n }\n\n private buildSpanPayload(\n span: AnyExportedSpan,\n isCreate: boolean,\n traceData: LangfuseTraceData,\n ): 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 }\n\n if (span.input !== undefined) payload.input = span.input;\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 const metadata: Record<string, any> = {\n ...span.metadata,\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 // 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 promptData = this.findLangfusePrompt(traceData, span);\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 /**\n * Force flush any buffered data to Langfuse without shutting down.\n */\n protected override async _flush(): Promise<void> {\n if (this.#client) {\n await this.#client.flushAsync();\n }\n }\n\n override async _postShutdown(): Promise<void> {\n if (this.#client) {\n await this.#client.shutdownAsync();\n }\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/tracing.ts","../src/helpers.ts"],"names":["BaseExporter","LangfuseSpanProcessor","LangfuseClient","SpanConverter","TracingEventType"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Langfuse Exporter for Mastra Observability\n *\n * Sends observability data to Langfuse using the official @langfuse/otel span processor\n * and @langfuse/client for non-tracing features (scoring, prompt management, evaluations).\n *\n * @see https://langfuse.com/docs/observability/sdk/typescript/overview\n */\n\nimport { LangfuseClient } from '@langfuse/client';\nimport { LangfuseSpanProcessor } from '@langfuse/otel';\nimport type { TracingEvent, AnyExportedSpan, InitExporterOptions } from '@mastra/core/observability';\nimport { TracingEventType } from '@mastra/core/observability';\nimport { BaseExporter } from '@mastra/observability';\nimport type { BaseExporterConfig } from '@mastra/observability';\nimport { SpanConverter } from '@mastra/otel-exporter';\n\nconst LOG_PREFIX = '[LangfuseExporter]';\n\nexport const LANGFUSE_DEFAULT_BASE_URL = 'https://cloud.langfuse.com';\n\nexport interface LangfuseExporterConfig extends BaseExporterConfig {\n /** Langfuse public key */\n publicKey?: string;\n /** Langfuse secret key */\n secretKey?: string;\n /** Langfuse host URL (defaults to https://cloud.langfuse.com) */\n baseUrl?: string;\n /** Enable realtime mode - flushes after each event for immediate visibility */\n realtime?: boolean;\n /** Langfuse environment tag for traces */\n environment?: string;\n /** Langfuse release tag for traces */\n release?: string;\n}\n\nexport class LangfuseExporter extends BaseExporter {\n name = 'langfuse';\n #processor: LangfuseSpanProcessor | undefined;\n #client: LangfuseClient | undefined;\n #spanConverter: SpanConverter | undefined;\n #realtime: boolean;\n #environment: string | undefined;\n #release: string | undefined;\n\n constructor(config: LangfuseExporterConfig = {}) {\n super(config);\n\n const publicKey = config.publicKey ?? process.env.LANGFUSE_PUBLIC_KEY;\n const secretKey = config.secretKey ?? process.env.LANGFUSE_SECRET_KEY;\n const baseUrl = (config.baseUrl ?? process.env.LANGFUSE_BASE_URL ?? LANGFUSE_DEFAULT_BASE_URL).replace(/\\/+$/, '');\n this.#realtime = config.realtime ?? false;\n\n if (!publicKey || !secretKey) {\n const publicKeySource = config.publicKey\n ? 'from config'\n : process.env.LANGFUSE_PUBLIC_KEY\n ? 'from env'\n : 'missing';\n const secretKeySource = config.secretKey\n ? 'from config'\n : process.env.LANGFUSE_SECRET_KEY\n ? 'from env'\n : 'missing';\n this.setDisabled(\n `${LOG_PREFIX} Missing required credentials (publicKey: ${publicKeySource}, secretKey: ${secretKeySource}). ` +\n `Set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY environment variables or pass them in config.`,\n );\n return;\n }\n\n this.#processor = new LangfuseSpanProcessor({\n publicKey,\n secretKey,\n baseUrl,\n environment: config.environment,\n release: config.release,\n exportMode: this.#realtime ? 'immediate' : 'batched',\n // Export all spans — the default filter only passes spans with gen_ai.* attributes\n // or known LLM instrumentation scopes, but Mastra spans use mastra.* attributes.\n shouldExportSpan: () => true,\n });\n\n this.#client = new LangfuseClient({\n publicKey,\n secretKey,\n baseUrl,\n });\n\n this.#environment = config.environment ?? process.env.LANGFUSE_TRACING_ENVIRONMENT;\n this.#release = config.release ?? process.env.LANGFUSE_RELEASE;\n }\n\n init(options: InitExporterOptions) {\n this.#spanConverter = new SpanConverter({\n packageName: '@mastra/langfuse',\n serviceName: options.config?.serviceName,\n format: 'GenAI_v1_38_0',\n });\n }\n\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n if (event.type !== TracingEventType.SPAN_ENDED) return;\n if (!this.#processor) return;\n\n await this.exportSpan(event.exportedSpan);\n }\n\n private async exportSpan(span: AnyExportedSpan): Promise<void> {\n if (!this.#spanConverter) {\n // Fallback if init() was not called (e.g., standalone usage without Mastra)\n this.#spanConverter = new SpanConverter({\n packageName: '@mastra/langfuse',\n serviceName: 'mastra-service',\n format: 'GenAI_v1_38_0',\n });\n }\n\n try {\n const otelSpan = await this.#spanConverter.convertSpan(span);\n\n // Map mastra.* attributes to langfuse.* namespace so that Langfuse's OTLP\n // endpoint reads them correctly. SpanConverter produces mastra.* attributes,\n // but Langfuse only reads langfuse.* attributes for prompt linking, TTFT, etc.\n // @see https://langfuse.com/integrations/native/opentelemetry#property-mapping\n mapMastraToLangfuseAttributes(otelSpan.attributes, this.#environment, this.#release);\n\n this.#processor!.onEnd(otelSpan);\n } catch (error) {\n this.logger.error(`${LOG_PREFIX} Failed to export span ${span.id}:`, error);\n }\n }\n\n /**\n * The LangfuseClient instance for advanced Langfuse features.\n * Use this for prompt management, evaluations, datasets, and direct API access.\n */\n get client(): LangfuseClient | undefined {\n return this.#client;\n }\n\n /**\n * Add a score to a trace via the Langfuse client.\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 this.#client.score.create({\n id: `${traceId}-${spanId || ''}-${scorerName}`,\n traceId,\n ...(spanId ? { observationId: spanId } : {}),\n name: scorerName,\n value: score,\n ...(reason ? { comment: reason } : {}),\n ...(metadata ? { metadata } : {}),\n dataType: 'NUMERIC' as const,\n });\n } catch (error) {\n this.logger.error(`${LOG_PREFIX} Error adding score to trace`, {\n error,\n traceId,\n spanId,\n scorerName,\n });\n }\n }\n\n async flush(): Promise<void> {\n await Promise.all([this.#processor?.forceFlush(), this.#client?.flush()]);\n }\n\n async shutdown(): Promise<void> {\n await Promise.all([this.#processor?.shutdown(), this.#client?.shutdown()]);\n }\n}\n\n/**\n * Maps Mastra-specific OTel attributes to the langfuse.* namespace that\n * Langfuse's OTLP endpoint reads for prompt linking, TTFT, and other features.\n *\n * SpanConverter produces attributes like mastra.metadata.*, mastra.completion_start_time, etc.\n * Langfuse's OTLP server only reads langfuse.observation.prompt.name, langfuse.observation.completion_start_time, etc.\n *\n * This function mutates the attributes object in place.\n * @see https://langfuse.com/integrations/native/opentelemetry#property-mapping\n */\nfunction mapMastraToLangfuseAttributes(attributes: Record<string, any>, environment?: string, release?: string): void {\n // Environment and release: set directly since onStart() is not called\n if (environment) {\n attributes['langfuse.environment'] = environment;\n }\n if (release) {\n attributes['langfuse.release'] = release;\n }\n\n // Prompt linking: mastra.metadata.langfuse → langfuse.observation.prompt.name / version\n const langfuseMetadata = attributes['mastra.metadata.langfuse'];\n if (langfuseMetadata) {\n try {\n const parsed = typeof langfuseMetadata === 'string' ? JSON.parse(langfuseMetadata) : langfuseMetadata;\n if (parsed?.prompt) {\n if (parsed.prompt.name !== undefined) {\n attributes['langfuse.observation.prompt.name'] = parsed.prompt.name;\n }\n if (parsed.prompt.version !== undefined) {\n attributes['langfuse.observation.prompt.version'] = parsed.prompt.version;\n }\n }\n } catch {\n // best effort — invalid JSON is silently ignored\n }\n delete attributes['mastra.metadata.langfuse'];\n }\n\n // TTFT: mastra.completion_start_time → langfuse.observation.completion_start_time\n if (attributes['mastra.completion_start_time']) {\n attributes['langfuse.observation.completion_start_time'] = attributes['mastra.completion_start_time'];\n delete attributes['mastra.completion_start_time'];\n }\n\n // User ID: mastra.metadata.userId → user.id\n if (attributes['mastra.metadata.userId']) {\n attributes['user.id'] = attributes['mastra.metadata.userId'];\n delete attributes['mastra.metadata.userId'];\n }\n\n // Session ID: mastra.metadata.sessionId or threadId → session.id\n const sessionId = attributes['mastra.metadata.sessionId'] ?? attributes['mastra.metadata.threadId'];\n if (sessionId) {\n attributes['session.id'] = sessionId;\n delete attributes['mastra.metadata.sessionId'];\n delete attributes['mastra.metadata.threadId'];\n }\n\n // Tags: mastra.tags → langfuse.trace.tags\n if (attributes['mastra.tags']) {\n attributes['langfuse.trace.tags'] = attributes['mastra.tags'];\n delete attributes['mastra.tags'];\n }\n\n // Input/Output: mastra.*.input/output → langfuse.observation.input/output\n // For gen_ai spans, Langfuse reads gen_ai.input.messages natively.\n // For non-gen_ai spans, we map the first mastra.*.input/output we find.\n if (!attributes['gen_ai.input.messages'] && !attributes['gen_ai.tool.call.arguments']) {\n for (const key of Object.keys(attributes)) {\n if (key.startsWith('mastra.') && key.endsWith('.input')) {\n attributes['langfuse.observation.input'] = attributes[key];\n break;\n }\n }\n }\n if (!attributes['gen_ai.output.messages'] && !attributes['gen_ai.tool.call.result']) {\n for (const key of Object.keys(attributes)) {\n if (key.startsWith('mastra.') && key.endsWith('.output')) {\n attributes['langfuse.observation.output'] = attributes[key];\n break;\n }\n }\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 agent = new Agent({\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangfusePrompt({ name: 'my-prompt', version: 1 }),\n * ),\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 /** @deprecated Langfuse v5 only supports linking by name + version. This field is ignored. */\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 (required for Langfuse v5)\n * - `version` - Prompt version (required for Langfuse v5)\n *\n * All fields are deeply merged with any existing metadata.\n *\n * @param prompt - Prompt fields for linking (`name` and `version` required)\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 *\n * // Link a generation to a Langfuse prompt by name and version\n * const tracingOptions = buildTracingOptions(\n * withLangfusePrompt({ name: 'customer-support', version: 1 }),\n * );\n *\n * // Or directly in agent config\n * const agent = new Agent({\n * name: 'support-agent',\n * instructions: 'You are a helpful assistant',\n * model: openai('gpt-4o'),\n * defaultGenerateOptions: {\n * tracingOptions: buildTracingOptions(\n * withLangfusePrompt({ name: 'my-prompt', version: 1 }),\n * ),\n * },\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,7 @@
|
|
|
2
2
|
* Langfuse Observability Provider for Mastra
|
|
3
3
|
*
|
|
4
4
|
* This package provides Langfuse-specific observability features for Mastra applications.
|
|
5
|
-
*
|
|
5
|
+
* Uses the official Langfuse v5 SDK (@langfuse/otel + @langfuse/client) for full feature support.
|
|
6
6
|
*/
|
|
7
7
|
export * from './tracing.js';
|
|
8
8
|
export * from './helpers.js';
|