@mastra/langfuse 0.0.0-add-libsql-changeset-20250910154739

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 ADDED
@@ -0,0 +1,181 @@
1
+ # @mastra/langfuse
2
+
3
+ ## 0.0.0-add-libsql-changeset-20250910154739
4
+
5
+ ### Patch Changes
6
+
7
+ - "updated observability config" ([#7641](https://github.com/mastra-ai/mastra/pull/7641))
8
+
9
+ - Updated dependencies [[`b4379f7`](https://github.com/mastra-ai/mastra/commit/b4379f703fd74474f253420e8c3a684f2c4b2f8e), [`d34aaa1`](https://github.com/mastra-ai/mastra/commit/d34aaa1da5d3c5f991740f59e2fe6d28d3e2dd91), [`b2babfa`](https://github.com/mastra-ai/mastra/commit/b2babfa9e75b22f2759179e71d8473f6dc5421ed), [`d8c3ba5`](https://github.com/mastra-ai/mastra/commit/d8c3ba516f4173282d293f7e64769cfc8738d360), [`6424c7e`](https://github.com/mastra-ai/mastra/commit/6424c7ec38b6921d66212431db1e0958f441b2a7), [`db94750`](https://github.com/mastra-ai/mastra/commit/db94750a41fd29b43eb1f7ce8e97ba8b9978c91b), [`a66a371`](https://github.com/mastra-ai/mastra/commit/a66a3716b00553d7f01842be9deb34f720b10fab), [`69fc3cd`](https://github.com/mastra-ai/mastra/commit/69fc3cd0fd814901785bdcf49bf536ab1e7fd975)]:
10
+ - @mastra/core@0.0.0-add-libsql-changeset-20250910154739
11
+
12
+ ## 0.0.6
13
+
14
+ ### Patch Changes
15
+
16
+ - 209250e: Simplified langfuse exporter config
17
+ - 376913a: Update peerdeps
18
+ - Updated dependencies [8fbf79e]
19
+ - Updated dependencies [fd83526]
20
+ - Updated dependencies [d0b90ab]
21
+ - Updated dependencies [6f5eb7a]
22
+ - Updated dependencies [a01cf14]
23
+ - Updated dependencies [a9e50ee]
24
+ - Updated dependencies [5397eb4]
25
+ - Updated dependencies [c9f4e4a]
26
+ - Updated dependencies [0acbc80]
27
+ - @mastra/core@0.16.0
28
+
29
+ ## 0.0.6-alpha.1
30
+
31
+ ### Patch Changes
32
+
33
+ - 376913a: Update peerdeps
34
+ - Updated dependencies [8fbf79e]
35
+ - @mastra/core@0.16.0-alpha.1
36
+
37
+ ## 0.0.6-alpha.0
38
+
39
+ ### Patch Changes
40
+
41
+ - 209250e: Simplified langfuse exporter config
42
+ - Updated dependencies [fd83526]
43
+ - Updated dependencies [d0b90ab]
44
+ - Updated dependencies [6f5eb7a]
45
+ - Updated dependencies [a01cf14]
46
+ - Updated dependencies [a9e50ee]
47
+ - Updated dependencies [5397eb4]
48
+ - Updated dependencies [c9f4e4a]
49
+ - Updated dependencies [0acbc80]
50
+ - @mastra/core@0.16.0-alpha.0
51
+
52
+ ## 0.0.5
53
+
54
+ ### Patch Changes
55
+
56
+ - de3cbc6: Update the `package.json` file to include additional fields like `repository`, `homepage` or `files`.
57
+ - 979912c: "Updated langfuse exporter to handle Event spans"
58
+ - Updated dependencies [ab48c97]
59
+ - Updated dependencies [85ef90b]
60
+ - Updated dependencies [aedbbfa]
61
+ - Updated dependencies [ff89505]
62
+ - Updated dependencies [637f323]
63
+ - Updated dependencies [de3cbc6]
64
+ - Updated dependencies [c19bcf7]
65
+ - Updated dependencies [4474d04]
66
+ - Updated dependencies [183dc95]
67
+ - Updated dependencies [a1111e2]
68
+ - Updated dependencies [b42a961]
69
+ - Updated dependencies [61debef]
70
+ - Updated dependencies [9beaeff]
71
+ - Updated dependencies [29de0e1]
72
+ - Updated dependencies [f643c65]
73
+ - Updated dependencies [00c74e7]
74
+ - Updated dependencies [fef7375]
75
+ - Updated dependencies [e3d8fea]
76
+ - Updated dependencies [45e4d39]
77
+ - Updated dependencies [9eee594]
78
+ - Updated dependencies [7149d8d]
79
+ - Updated dependencies [822c2e8]
80
+ - Updated dependencies [979912c]
81
+ - Updated dependencies [7dcf4c0]
82
+ - Updated dependencies [4106a58]
83
+ - Updated dependencies [ad78bfc]
84
+ - Updated dependencies [0302f50]
85
+ - Updated dependencies [6ac697e]
86
+ - Updated dependencies [74db265]
87
+ - Updated dependencies [0ce418a]
88
+ - Updated dependencies [af90672]
89
+ - Updated dependencies [8387952]
90
+ - Updated dependencies [7f3b8da]
91
+ - Updated dependencies [905352b]
92
+ - Updated dependencies [599d04c]
93
+ - Updated dependencies [56041d0]
94
+ - Updated dependencies [3412597]
95
+ - Updated dependencies [5eca5d2]
96
+ - Updated dependencies [f2cda47]
97
+ - Updated dependencies [5de1555]
98
+ - Updated dependencies [cfd377a]
99
+ - Updated dependencies [1ed5a3e]
100
+ - @mastra/core@0.15.3
101
+
102
+ ## 0.0.5-alpha.1
103
+
104
+ ### Patch Changes
105
+
106
+ - [#7343](https://github.com/mastra-ai/mastra/pull/7343) [`de3cbc6`](https://github.com/mastra-ai/mastra/commit/de3cbc61079211431bd30487982ea3653517278e) Thanks [@LekoArts](https://github.com/LekoArts)! - Update the `package.json` file to include additional fields like `repository`, `homepage` or `files`.
107
+
108
+ - Updated dependencies [[`85ef90b`](https://github.com/mastra-ai/mastra/commit/85ef90bb2cd4ae4df855c7ac175f7d392c55c1bf), [`de3cbc6`](https://github.com/mastra-ai/mastra/commit/de3cbc61079211431bd30487982ea3653517278e)]:
109
+ - @mastra/core@0.15.3-alpha.5
110
+
111
+ ## 0.0.5-alpha.0
112
+
113
+ ### Patch Changes
114
+
115
+ - [#7266](https://github.com/mastra-ai/mastra/pull/7266) [`979912c`](https://github.com/mastra-ai/mastra/commit/979912cfd180aad53287cda08af771df26454e2c) Thanks [@epinzur](https://github.com/epinzur)! - "Updated langfuse exporter to handle Event spans"
116
+
117
+ - Updated dependencies [[`ab48c97`](https://github.com/mastra-ai/mastra/commit/ab48c979098ea571faf998a55d3a00e7acd7a715), [`ff89505`](https://github.com/mastra-ai/mastra/commit/ff895057c8c7e91a5535faef46c5e5391085ddfa), [`183dc95`](https://github.com/mastra-ai/mastra/commit/183dc95596f391b977bd1a2c050b8498dac74891), [`a1111e2`](https://github.com/mastra-ai/mastra/commit/a1111e24e705488adfe5e0a6f20c53bddf26cb22), [`61debef`](https://github.com/mastra-ai/mastra/commit/61debefd80ad3a7ed5737e19df6a23d40091689a), [`9beaeff`](https://github.com/mastra-ai/mastra/commit/9beaeffa4a97b1d5fd01a7f8af8708b16067f67c), [`9eee594`](https://github.com/mastra-ai/mastra/commit/9eee594e35e0ca2a650fcc33fa82009a142b9ed0), [`979912c`](https://github.com/mastra-ai/mastra/commit/979912cfd180aad53287cda08af771df26454e2c), [`7dcf4c0`](https://github.com/mastra-ai/mastra/commit/7dcf4c04f44d9345b1f8bc5d41eae3f11ac61611), [`ad78bfc`](https://github.com/mastra-ai/mastra/commit/ad78bfc4ea6a1fff140432bf4f638e01af7af668), [`0ce418a`](https://github.com/mastra-ai/mastra/commit/0ce418a1ccaa5e125d4483a9651b635046152569), [`8387952`](https://github.com/mastra-ai/mastra/commit/838795227b4edf758c84a2adf6f7fba206c27719), [`5eca5d2`](https://github.com/mastra-ai/mastra/commit/5eca5d2655788863ea0442a46c9ef5d3c6dbe0a8)]:
118
+ - @mastra/core@0.15.3-alpha.4
119
+
120
+ ## 0.0.4
121
+
122
+ ### Patch Changes
123
+
124
+ - [`c6113ed`](https://github.com/mastra-ai/mastra/commit/c6113ed7f9df297e130d94436ceee310273d6430) Thanks [@wardpeet](https://github.com/wardpeet)! - Fix peerdpes for @mastra/core
125
+
126
+ - Updated dependencies []:
127
+ - @mastra/core@0.15.2
128
+
129
+ ## 0.0.3
130
+
131
+ ### Patch Changes
132
+
133
+ - [`95b2aa9`](https://github.com/mastra-ai/mastra/commit/95b2aa908230919e67efcac0d69005a2d5745298) Thanks [@wardpeet](https://github.com/wardpeet)! - Fix peerdeps @mastra/core
134
+
135
+ - Updated dependencies []:
136
+ - @mastra/core@0.15.1
137
+
138
+ ## 0.0.2
139
+
140
+ ### Patch Changes
141
+
142
+ - 03997ae: Update peerdeps
143
+ - e1a81da: initial release of LangFuse AI Observability exporter
144
+ - Updated dependencies [227c7e6]
145
+ - Updated dependencies [12cae67]
146
+ - Updated dependencies [fd3a3eb]
147
+ - Updated dependencies [6faaee5]
148
+ - Updated dependencies [4232b14]
149
+ - Updated dependencies [a89de7e]
150
+ - Updated dependencies [5a37d0c]
151
+ - Updated dependencies [4bde0cb]
152
+ - Updated dependencies [cf4f357]
153
+ - Updated dependencies [ad888a2]
154
+ - Updated dependencies [481751d]
155
+ - Updated dependencies [2454423]
156
+ - Updated dependencies [194e395]
157
+ - Updated dependencies [a722c0b]
158
+ - Updated dependencies [c30bca8]
159
+ - Updated dependencies [3b5fec7]
160
+ - Updated dependencies [a8f129d]
161
+ - @mastra/core@0.14.0
162
+
163
+ ## 0.0.2-alpha.1
164
+
165
+ ### Patch Changes
166
+
167
+ - 03997ae: Update peerdeps
168
+ - @mastra/core@0.14.0-alpha.7
169
+
170
+ ## 0.0.2-alpha.0
171
+
172
+ ### Patch Changes
173
+
174
+ - e1a81da: initial release of LangFuse AI Observability exporter
175
+ - Updated dependencies [6faaee5]
176
+ - Updated dependencies [4232b14]
177
+ - Updated dependencies [a89de7e]
178
+ - Updated dependencies [cf4f357]
179
+ - Updated dependencies [a722c0b]
180
+ - Updated dependencies [3b5fec7]
181
+ - @mastra/core@0.14.0-alpha.1
package/LICENSE.md ADDED
@@ -0,0 +1,15 @@
1
+ # Apache License 2.0
2
+
3
+ Copyright (c) 2025 Kepler Software, Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @mastra/langfuse
2
+
3
+ Langfuse AI Observability exporter for Mastra applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @mastra/langfuse
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { LangfuseExporter } from '@mastra/langfuse';
15
+
16
+ // Use with Mastra
17
+ const mastra = new Mastra({
18
+ ...,
19
+ observability: {
20
+ configs: {
21
+ langfuse: {
22
+ serviceName: 'service',
23
+ exporters: [
24
+ new LangfuseExporter({
25
+ publicKey: process.env.LANGFUSE_PUBLIC_KEY,
26
+ secretKey: process.env.LANGFUSE_SECRET_KEY,
27
+ baseUrl: process.env.LANGFUSE_BASE_URL, // Optional - defaults to Langfuse cloud
28
+ realtime: true,
29
+ }),
30
+ ],
31
+ },
32
+ },
33
+ },
34
+ });
35
+ ```
36
+
37
+ ## Features
38
+
39
+ ### AI Tracing
40
+
41
+ - **Automatic span mapping**: Root spans become Langfuse traces
42
+ - **LLM generation support**: `LLM_GENERATION` spans become Langfuse generations with token usage
43
+ - **Type-specific metadata**: Extracts relevant metadata for each span type (agents, tools, workflows)
44
+ - **Error tracking**: Automatic error status and message tracking
45
+ - **Hierarchical traces**: Maintains parent-child relationships
46
+
47
+ ## License
48
+
49
+ Apache 2.0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Langfuse Exporter for Mastra AI Tracing
3
+ *
4
+ * This exporter sends tracing data to Langfuse for AI observability.
5
+ * Root spans start traces in Langfuse.
6
+ * LLM_GENERATION spans become Langfuse generations, all others become spans.
7
+ */
8
+ import type { AITracingExporter, AITracingEvent } from '@mastra/core/ai-tracing';
9
+ export interface LangfuseExporterConfig {
10
+ /** Langfuse API key */
11
+ publicKey?: string;
12
+ /** Langfuse secret key */
13
+ secretKey?: string;
14
+ /** Langfuse host URL */
15
+ baseUrl?: string;
16
+ /** Enable realtime mode - flushes after each event for immediate visibility */
17
+ realtime?: boolean;
18
+ /** Logger level for diagnostic messages (default: 'warn') */
19
+ logLevel?: 'debug' | 'info' | 'warn' | 'error';
20
+ /** Additional options to pass to the Langfuse client */
21
+ options?: any;
22
+ }
23
+ export declare class LangfuseExporter implements AITracingExporter {
24
+ name: string;
25
+ private client;
26
+ private realtime;
27
+ private traceMap;
28
+ private logger;
29
+ constructor(config: LangfuseExporterConfig);
30
+ exportEvent(event: AITracingEvent): Promise<void>;
31
+ private handleSpanStarted;
32
+ private handleSpanUpdateOrEnd;
33
+ private handleEventSpan;
34
+ private initTrace;
35
+ private getTraceData;
36
+ private getLangfuseParent;
37
+ private buildTracePayload;
38
+ private buildSpanPayload;
39
+ shutdown(): Promise<void>;
40
+ }
41
+ //# sourceMappingURL=ai-tracing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-tracing.d.ts","sourceRoot":"","sources":["../src/ai-tracing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAsC,MAAM,yBAAyB,CAAC;AAMrH,MAAM,WAAW,sBAAsB;IACrC,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/C,wDAAwD;IACxD,OAAO,CAAC,EAAE,GAAG,CAAC;CACf;AAUD,qBAAa,gBAAiB,YAAW,iBAAiB;IACxD,IAAI,SAAc;IAClB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,sBAAsB;IAsBpC,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;YA6BzC,iBAAiB;YAwBjB,qBAAqB;YAgCrB,eAAe;IA6B7B,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,gBAAgB;IAmDlB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAMhC"}
package/dist/index.cjs ADDED
@@ -0,0 +1,225 @@
1
+ 'use strict';
2
+
3
+ var aiTracing = require('@mastra/core/ai-tracing');
4
+ var logger = require('@mastra/core/logger');
5
+ var langfuse = require('langfuse');
6
+
7
+ // src/ai-tracing.ts
8
+ var LangfuseExporter = class {
9
+ name = "langfuse";
10
+ client;
11
+ realtime;
12
+ traceMap = /* @__PURE__ */ new Map();
13
+ logger;
14
+ constructor(config) {
15
+ this.realtime = config.realtime ?? false;
16
+ this.logger = new logger.ConsoleLogger({ level: config.logLevel ?? "warn" });
17
+ 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
+ });
22
+ this.client = null;
23
+ return;
24
+ }
25
+ this.client = new langfuse.Langfuse({
26
+ publicKey: config.publicKey,
27
+ secretKey: config.secretKey,
28
+ baseUrl: config.baseUrl,
29
+ ...config.options
30
+ });
31
+ }
32
+ async exportEvent(event) {
33
+ if (!this.client) {
34
+ return;
35
+ }
36
+ if (event.span.isEvent) {
37
+ await this.handleEventSpan(event.span);
38
+ return;
39
+ }
40
+ switch (event.type) {
41
+ case "span_started":
42
+ await this.handleSpanStarted(event.span);
43
+ break;
44
+ case "span_updated":
45
+ await this.handleSpanUpdateOrEnd(event.span, false);
46
+ break;
47
+ case "span_ended":
48
+ await this.handleSpanUpdateOrEnd(event.span, true);
49
+ break;
50
+ }
51
+ if (this.realtime) {
52
+ await this.client.flushAsync();
53
+ }
54
+ }
55
+ async handleSpanStarted(span) {
56
+ if (span.isRootSpan) {
57
+ this.initTrace(span);
58
+ }
59
+ const method = "handleSpanStarted";
60
+ const traceData = this.getTraceData({ span, method });
61
+ if (!traceData) {
62
+ return;
63
+ }
64
+ const langfuseParent = this.getLangfuseParent({ traceData, span, method });
65
+ if (!langfuseParent) {
66
+ return;
67
+ }
68
+ const payload = this.buildSpanPayload(span, true);
69
+ const langfuseSpan = span.type === aiTracing.AISpanType.LLM_GENERATION ? langfuseParent.generation(payload) : langfuseParent.span(payload);
70
+ traceData.spans.set(span.id, langfuseSpan);
71
+ }
72
+ async handleSpanUpdateOrEnd(span, isEnd) {
73
+ const method = isEnd ? "handleSpanEnd" : "handleSpanUpdate";
74
+ const traceData = this.getTraceData({ span, method });
75
+ if (!traceData) {
76
+ return;
77
+ }
78
+ const langfuseSpan = traceData.spans.get(span.id);
79
+ if (!langfuseSpan) {
80
+ this.logger.warn("Langfuse exporter: No Langfuse span found for span update/end", {
81
+ traceId: span.traceId,
82
+ spanId: span.id,
83
+ spanName: span.name,
84
+ spanType: span.type,
85
+ isRootSpan: span.isRootSpan,
86
+ parentSpanId: span.parent?.id,
87
+ method
88
+ });
89
+ return;
90
+ }
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);
95
+ }
96
+ }
97
+ async handleEventSpan(span) {
98
+ if (span.isRootSpan) {
99
+ this.logger.debug("Langfuse exporter: Creating trace", {
100
+ traceId: span.traceId,
101
+ spanId: span.id,
102
+ spanName: span.name,
103
+ method: "handleEventSpan"
104
+ });
105
+ this.initTrace(span);
106
+ }
107
+ const method = "handleEventSpan";
108
+ const traceData = this.getTraceData({ span, method });
109
+ if (!traceData) {
110
+ return;
111
+ }
112
+ const langfuseParent = this.getLangfuseParent({ traceData, span, method });
113
+ if (!langfuseParent) {
114
+ return;
115
+ }
116
+ const payload = this.buildSpanPayload(span, true);
117
+ const langfuseEvent = langfuseParent.event(payload);
118
+ traceData.events.set(span.id, langfuseEvent);
119
+ }
120
+ initTrace(span) {
121
+ const trace = this.client.trace(this.buildTracePayload(span));
122
+ this.traceMap.set(span.traceId, { trace, spans: /* @__PURE__ */ new Map(), events: /* @__PURE__ */ new Map() });
123
+ }
124
+ getTraceData(options) {
125
+ const { span, method } = options;
126
+ if (this.traceMap.has(span.traceId)) {
127
+ return this.traceMap.get(span.traceId);
128
+ }
129
+ this.logger.warn("Langfuse exporter: No trace data found for span", {
130
+ traceId: span.traceId,
131
+ spanId: span.id,
132
+ spanName: span.name,
133
+ spanType: span.type,
134
+ isRootSpan: span.isRootSpan,
135
+ parentSpanId: span.parent?.id,
136
+ method
137
+ });
138
+ }
139
+ getLangfuseParent(options) {
140
+ const { traceData, span, method } = options;
141
+ const parentId = span.parent?.id;
142
+ if (!parentId) {
143
+ return traceData.trace;
144
+ }
145
+ if (traceData.spans.has(parentId)) {
146
+ return traceData.spans.get(parentId);
147
+ }
148
+ if (traceData.events.has(parentId)) {
149
+ return traceData.events.get(parentId);
150
+ }
151
+ this.logger.warn("Langfuse exporter: No parent data found for span", {
152
+ traceId: span.traceId,
153
+ spanId: span.id,
154
+ spanName: span.name,
155
+ spanType: span.type,
156
+ isRootSpan: span.isRootSpan,
157
+ parentSpanId: span.parent?.id,
158
+ method
159
+ });
160
+ }
161
+ buildTracePayload(span) {
162
+ const payload = {
163
+ id: span.traceId,
164
+ name: span.name
165
+ };
166
+ const { userId, sessionId, ...remainingMetadata } = span.metadata ?? {};
167
+ if (userId) payload.userId = userId;
168
+ if (sessionId) payload.sessionId = sessionId;
169
+ if (span.input) payload.input = span.input;
170
+ payload.metadata = {
171
+ spanType: span.type,
172
+ ...span.attributes,
173
+ ...remainingMetadata
174
+ };
175
+ return payload;
176
+ }
177
+ buildSpanPayload(span, isCreate) {
178
+ const payload = {};
179
+ if (isCreate) {
180
+ payload.id = span.id;
181
+ payload.name = span.name;
182
+ payload.startTime = span.startTime;
183
+ if (span.input !== void 0) payload.input = span.input;
184
+ }
185
+ if (span.output !== void 0) payload.output = span.output;
186
+ if (span.endTime !== void 0) payload.endTime = span.endTime;
187
+ const attributes = span.attributes ?? {};
188
+ 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;
193
+ attributesToOmit.push("model");
194
+ }
195
+ if (llmAttr.usage !== void 0) {
196
+ payload.usage = llmAttr.usage;
197
+ attributesToOmit.push("usage");
198
+ }
199
+ if (llmAttr.parameters !== void 0) {
200
+ payload.modelParameters = llmAttr.parameters;
201
+ attributesToOmit.push("parameters");
202
+ }
203
+ }
204
+ payload.metadata = {
205
+ spanType: span.type,
206
+ ...aiTracing.omitKeys(attributes, attributesToOmit),
207
+ ...span.metadata
208
+ };
209
+ if (span.errorInfo) {
210
+ payload.level = "ERROR";
211
+ payload.statusMessage = span.errorInfo.message;
212
+ }
213
+ return payload;
214
+ }
215
+ async shutdown() {
216
+ if (this.client) {
217
+ await this.client.shutdownAsync();
218
+ }
219
+ this.traceMap.clear();
220
+ }
221
+ };
222
+
223
+ exports.LangfuseExporter = LangfuseExporter;
224
+ //# sourceMappingURL=index.cjs.map
225
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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 { AITracingExporter, AITracingEvent, AnyAISpan, LLMGenerationAttributes } 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.span.isEvent) {\n await this.handleEventSpan(event.span);\n return;\n }\n\n switch (event.type) {\n case 'span_started':\n await this.handleSpanStarted(event.span);\n break;\n case 'span_updated':\n await this.handleSpanUpdateOrEnd(event.span, false);\n break;\n case 'span_ended':\n await this.handleSpanUpdateOrEnd(event.span, 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: AnyAISpan): 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: AnyAISpan, 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.parent?.id,\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: AnyAISpan): 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: AnyAISpan): 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: AnyAISpan; 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.parent?.id,\n method,\n });\n }\n\n private getLangfuseParent(options: {\n traceData: TraceData;\n span: AnyAISpan;\n method: string;\n }): LangfuseParent | undefined {\n const { traceData, span, method } = options;\n\n const parentId = span.parent?.id;\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.parent?.id,\n method,\n });\n }\n\n private buildTracePayload(span: AnyAISpan): 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: AnyAISpan, 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"]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Langfuse Observability Provider for Mastra
3
+ *
4
+ * This package provides Langfuse-specific observability features for Mastra applications.
5
+ * Currently includes AI tracing support with plans for additional observability features.
6
+ */
7
+ export * from './ai-tracing.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,223 @@
1
+ import { AISpanType, omitKeys } from '@mastra/core/ai-tracing';
2
+ import { ConsoleLogger } from '@mastra/core/logger';
3
+ import { Langfuse } from 'langfuse';
4
+
5
+ // src/ai-tracing.ts
6
+ var LangfuseExporter = class {
7
+ name = "langfuse";
8
+ client;
9
+ realtime;
10
+ traceMap = /* @__PURE__ */ new Map();
11
+ logger;
12
+ constructor(config) {
13
+ this.realtime = config.realtime ?? false;
14
+ this.logger = new ConsoleLogger({ level: config.logLevel ?? "warn" });
15
+ if (!config.publicKey || !config.secretKey) {
16
+ this.logger.error("LangfuseExporter: Missing required credentials, exporter will be disabled", {
17
+ hasPublicKey: !!config.publicKey,
18
+ hasSecretKey: !!config.secretKey
19
+ });
20
+ this.client = null;
21
+ return;
22
+ }
23
+ this.client = new Langfuse({
24
+ publicKey: config.publicKey,
25
+ secretKey: config.secretKey,
26
+ baseUrl: config.baseUrl,
27
+ ...config.options
28
+ });
29
+ }
30
+ async exportEvent(event) {
31
+ if (!this.client) {
32
+ return;
33
+ }
34
+ if (event.span.isEvent) {
35
+ await this.handleEventSpan(event.span);
36
+ return;
37
+ }
38
+ switch (event.type) {
39
+ case "span_started":
40
+ await this.handleSpanStarted(event.span);
41
+ break;
42
+ case "span_updated":
43
+ await this.handleSpanUpdateOrEnd(event.span, false);
44
+ break;
45
+ case "span_ended":
46
+ await this.handleSpanUpdateOrEnd(event.span, true);
47
+ break;
48
+ }
49
+ if (this.realtime) {
50
+ await this.client.flushAsync();
51
+ }
52
+ }
53
+ async handleSpanStarted(span) {
54
+ if (span.isRootSpan) {
55
+ this.initTrace(span);
56
+ }
57
+ const method = "handleSpanStarted";
58
+ const traceData = this.getTraceData({ span, method });
59
+ if (!traceData) {
60
+ return;
61
+ }
62
+ const langfuseParent = this.getLangfuseParent({ traceData, span, method });
63
+ if (!langfuseParent) {
64
+ return;
65
+ }
66
+ const payload = this.buildSpanPayload(span, true);
67
+ const langfuseSpan = span.type === AISpanType.LLM_GENERATION ? langfuseParent.generation(payload) : langfuseParent.span(payload);
68
+ traceData.spans.set(span.id, langfuseSpan);
69
+ }
70
+ async handleSpanUpdateOrEnd(span, isEnd) {
71
+ const method = isEnd ? "handleSpanEnd" : "handleSpanUpdate";
72
+ const traceData = this.getTraceData({ span, method });
73
+ if (!traceData) {
74
+ return;
75
+ }
76
+ const langfuseSpan = traceData.spans.get(span.id);
77
+ if (!langfuseSpan) {
78
+ this.logger.warn("Langfuse exporter: No Langfuse span found for span update/end", {
79
+ traceId: span.traceId,
80
+ spanId: span.id,
81
+ spanName: span.name,
82
+ spanType: span.type,
83
+ isRootSpan: span.isRootSpan,
84
+ parentSpanId: span.parent?.id,
85
+ method
86
+ });
87
+ return;
88
+ }
89
+ langfuseSpan.update(this.buildSpanPayload(span, false));
90
+ if (isEnd && span.isRootSpan) {
91
+ traceData.trace.update({ output: span.output });
92
+ this.traceMap.delete(span.traceId);
93
+ }
94
+ }
95
+ async handleEventSpan(span) {
96
+ if (span.isRootSpan) {
97
+ this.logger.debug("Langfuse exporter: Creating trace", {
98
+ traceId: span.traceId,
99
+ spanId: span.id,
100
+ spanName: span.name,
101
+ method: "handleEventSpan"
102
+ });
103
+ this.initTrace(span);
104
+ }
105
+ const method = "handleEventSpan";
106
+ const traceData = this.getTraceData({ span, method });
107
+ if (!traceData) {
108
+ return;
109
+ }
110
+ const langfuseParent = this.getLangfuseParent({ traceData, span, method });
111
+ if (!langfuseParent) {
112
+ return;
113
+ }
114
+ const payload = this.buildSpanPayload(span, true);
115
+ const langfuseEvent = langfuseParent.event(payload);
116
+ traceData.events.set(span.id, langfuseEvent);
117
+ }
118
+ initTrace(span) {
119
+ const trace = this.client.trace(this.buildTracePayload(span));
120
+ this.traceMap.set(span.traceId, { trace, spans: /* @__PURE__ */ new Map(), events: /* @__PURE__ */ new Map() });
121
+ }
122
+ getTraceData(options) {
123
+ const { span, method } = options;
124
+ if (this.traceMap.has(span.traceId)) {
125
+ return this.traceMap.get(span.traceId);
126
+ }
127
+ this.logger.warn("Langfuse exporter: No trace data found for span", {
128
+ traceId: span.traceId,
129
+ spanId: span.id,
130
+ spanName: span.name,
131
+ spanType: span.type,
132
+ isRootSpan: span.isRootSpan,
133
+ parentSpanId: span.parent?.id,
134
+ method
135
+ });
136
+ }
137
+ getLangfuseParent(options) {
138
+ const { traceData, span, method } = options;
139
+ const parentId = span.parent?.id;
140
+ if (!parentId) {
141
+ return traceData.trace;
142
+ }
143
+ if (traceData.spans.has(parentId)) {
144
+ return traceData.spans.get(parentId);
145
+ }
146
+ if (traceData.events.has(parentId)) {
147
+ return traceData.events.get(parentId);
148
+ }
149
+ this.logger.warn("Langfuse exporter: No parent data found for span", {
150
+ traceId: span.traceId,
151
+ spanId: span.id,
152
+ spanName: span.name,
153
+ spanType: span.type,
154
+ isRootSpan: span.isRootSpan,
155
+ parentSpanId: span.parent?.id,
156
+ method
157
+ });
158
+ }
159
+ buildTracePayload(span) {
160
+ const payload = {
161
+ id: span.traceId,
162
+ name: span.name
163
+ };
164
+ const { userId, sessionId, ...remainingMetadata } = span.metadata ?? {};
165
+ if (userId) payload.userId = userId;
166
+ if (sessionId) payload.sessionId = sessionId;
167
+ if (span.input) payload.input = span.input;
168
+ payload.metadata = {
169
+ spanType: span.type,
170
+ ...span.attributes,
171
+ ...remainingMetadata
172
+ };
173
+ return payload;
174
+ }
175
+ buildSpanPayload(span, isCreate) {
176
+ const payload = {};
177
+ if (isCreate) {
178
+ payload.id = span.id;
179
+ payload.name = span.name;
180
+ payload.startTime = span.startTime;
181
+ if (span.input !== void 0) payload.input = span.input;
182
+ }
183
+ if (span.output !== void 0) payload.output = span.output;
184
+ if (span.endTime !== void 0) payload.endTime = span.endTime;
185
+ const attributes = span.attributes ?? {};
186
+ const attributesToOmit = [];
187
+ if (span.type === AISpanType.LLM_GENERATION) {
188
+ const llmAttr = attributes;
189
+ if (llmAttr.model !== void 0) {
190
+ payload.model = llmAttr.model;
191
+ attributesToOmit.push("model");
192
+ }
193
+ if (llmAttr.usage !== void 0) {
194
+ payload.usage = llmAttr.usage;
195
+ attributesToOmit.push("usage");
196
+ }
197
+ if (llmAttr.parameters !== void 0) {
198
+ payload.modelParameters = llmAttr.parameters;
199
+ attributesToOmit.push("parameters");
200
+ }
201
+ }
202
+ payload.metadata = {
203
+ spanType: span.type,
204
+ ...omitKeys(attributes, attributesToOmit),
205
+ ...span.metadata
206
+ };
207
+ if (span.errorInfo) {
208
+ payload.level = "ERROR";
209
+ payload.statusMessage = span.errorInfo.message;
210
+ }
211
+ return payload;
212
+ }
213
+ async shutdown() {
214
+ if (this.client) {
215
+ await this.client.shutdownAsync();
216
+ }
217
+ this.traceMap.clear();
218
+ }
219
+ };
220
+
221
+ export { LangfuseExporter };
222
+ //# sourceMappingURL=index.js.map
223
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ai-tracing.ts"],"names":[],"mappings":"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","file":"index.js","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 { AITracingExporter, AITracingEvent, AnyAISpan, LLMGenerationAttributes } 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.span.isEvent) {\n await this.handleEventSpan(event.span);\n return;\n }\n\n switch (event.type) {\n case 'span_started':\n await this.handleSpanStarted(event.span);\n break;\n case 'span_updated':\n await this.handleSpanUpdateOrEnd(event.span, false);\n break;\n case 'span_ended':\n await this.handleSpanUpdateOrEnd(event.span, 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: AnyAISpan): 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: AnyAISpan, 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.parent?.id,\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: AnyAISpan): 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: AnyAISpan): 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: AnyAISpan; 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.parent?.id,\n method,\n });\n }\n\n private getLangfuseParent(options: {\n traceData: TraceData;\n span: AnyAISpan;\n method: string;\n }): LangfuseParent | undefined {\n const { traceData, span, method } = options;\n\n const parentId = span.parent?.id;\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.parent?.id,\n method,\n });\n }\n\n private buildTracePayload(span: AnyAISpan): 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: AnyAISpan, 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"]}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@mastra/langfuse",
3
+ "version": "0.0.0-add-libsql-changeset-20250910154739",
4
+ "description": "Langfuse observability provider for Mastra - includes AI tracing and future observability features",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "CHANGELOG.md"
11
+ ],
12
+ "exports": {
13
+ ".": {
14
+ "import": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ },
18
+ "require": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.cjs"
21
+ }
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
25
+ "license": "Apache-2.0",
26
+ "dependencies": {
27
+ "langfuse": "^3.38.4"
28
+ },
29
+ "devDependencies": {
30
+ "@microsoft/api-extractor": "^7.52.8",
31
+ "@types/node": "^20.19.0",
32
+ "eslint": "^9.30.1",
33
+ "tsup": "^8.5.0",
34
+ "typescript": "^5.8.3",
35
+ "vitest": "^3.2.4",
36
+ "@internal/lint": "0.0.0-add-libsql-changeset-20250910154739",
37
+ "@internal/types-builder": "0.0.0-add-libsql-changeset-20250910154739",
38
+ "@mastra/core": "0.0.0-add-libsql-changeset-20250910154739"
39
+ },
40
+ "peerDependencies": {
41
+ "@mastra/core": "0.0.0-add-libsql-changeset-20250910154739"
42
+ },
43
+ "homepage": "https://mastra.ai",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/mastra-ai/mastra.git",
47
+ "directory": "observability/langfuse"
48
+ },
49
+ "bugs": {
50
+ "url": "https://github.com/mastra-ai/mastra/issues"
51
+ },
52
+ "scripts": {
53
+ "build": "tsup --silent --config tsup.config.ts",
54
+ "build:watch": "pnpm build --watch",
55
+ "test": "vitest run",
56
+ "test:watch": "vitest watch",
57
+ "lint": "eslint ."
58
+ }
59
+ }