@mastra/langfuse 1.0.0-beta.12 → 1.0.0-beta.14
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 +38 -0
- package/dist/index.cjs +8 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/tracing.d.ts +4 -0
- package/dist/tracing.d.ts.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# @mastra/langfuse
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.14
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Added `flush()` method to observability exporters and instances for serverless environments ([#12003](https://github.com/mastra-ai/mastra/pull/12003))
|
|
8
|
+
|
|
9
|
+
This feature allows flushing buffered spans without shutting down the exporter, which is useful in serverless environments like Vercel's fluid compute where runtime instances can be reused across multiple requests.
|
|
10
|
+
|
|
11
|
+
**New API:**
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// Flush all exporters via the observability instance
|
|
15
|
+
const observability = mastra.getObservability();
|
|
16
|
+
await observability.flush();
|
|
17
|
+
|
|
18
|
+
// Or flush individual exporters
|
|
19
|
+
const exporters = observability.getExporters();
|
|
20
|
+
await exporters[0].flush();
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Why this matters:**
|
|
24
|
+
|
|
25
|
+
In serverless environments, you may need to ensure all spans are exported before the runtime instance is terminated, while keeping the exporter active for future requests. Unlike shutdown(), flush() does not release resources or prevent future exports.
|
|
26
|
+
|
|
27
|
+
Closes #11372
|
|
28
|
+
|
|
29
|
+
- Updated dependencies [[`1dbd8c7`](https://github.com/mastra-ai/mastra/commit/1dbd8c729fb6536ec52f00064d76b80253d346e9), [`1dbd8c7`](https://github.com/mastra-ai/mastra/commit/1dbd8c729fb6536ec52f00064d76b80253d346e9), [`c59e13c`](https://github.com/mastra-ai/mastra/commit/c59e13c7688284bd96b2baee3e314335003548de), [`f9a2509`](https://github.com/mastra-ai/mastra/commit/f9a25093ea72d210a5e52cfcb3bcc8b5e02dc25c), [`7a010c5`](https://github.com/mastra-ai/mastra/commit/7a010c56b846a313a49ae42fccd3d8de2b9f292d)]:
|
|
30
|
+
- @mastra/core@1.0.0-beta.24
|
|
31
|
+
- @mastra/observability@1.0.0-beta.13
|
|
32
|
+
|
|
33
|
+
## 1.0.0-beta.13
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- Updated dependencies [[`c8417b4`](https://github.com/mastra-ai/mastra/commit/c8417b41d9f3486854dc7842d977fbe5e2166264), [`dd4f34c`](https://github.com/mastra-ai/mastra/commit/dd4f34c78cbae24063463475b0619575c415f9b8)]:
|
|
38
|
+
- @mastra/core@1.0.0-beta.23
|
|
39
|
+
- @mastra/observability@1.0.0-beta.12
|
|
40
|
+
|
|
3
41
|
## 1.0.0-beta.12
|
|
4
42
|
|
|
5
43
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -256,6 +256,14 @@ var LangfuseExporter = class extends observability.TrackingExporter {
|
|
|
256
256
|
});
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Force flush any buffered data to Langfuse without shutting down.
|
|
261
|
+
*/
|
|
262
|
+
async _flush() {
|
|
263
|
+
if (this.#client) {
|
|
264
|
+
await this.#client.flushAsync();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
259
267
|
async _postShutdown() {
|
|
260
268
|
if (this.#client) {
|
|
261
269
|
await this.#client.shutdownAsync();
|
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 metrics.input = usage.inputTokens;\n\n if (usage.inputDetails?.cacheWrite !== undefined) {\n metrics.cache_write_input_tokens = usage.inputDetails.cacheWrite;\n metrics.input -= metrics.cache_write_input_tokens;\n }\n }\n\n if (usage.inputDetails?.cacheRead !== undefined) {\n metrics.cache_read_input_tokens = usage.inputDetails.cacheRead;\n }\n\n if (usage.outputTokens !== undefined) {\n metrics.output = usage.outputTokens;\n }\n\n if (usage.outputDetails?.reasoning !== undefined) {\n metrics.reasoning = usage.outputDetails.reasoning;\n }\n\n // 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_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 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/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 metrics.input = usage.inputTokens;\n\n if (usage.inputDetails?.cacheWrite !== undefined) {\n metrics.cache_write_input_tokens = usage.inputDetails.cacheWrite;\n metrics.input -= metrics.cache_write_input_tokens;\n }\n }\n\n if (usage.inputDetails?.cacheRead !== undefined) {\n metrics.cache_read_input_tokens = usage.inputDetails.cacheRead;\n }\n\n if (usage.outputTokens !== undefined) {\n metrics.output = usage.outputTokens;\n }\n\n if (usage.outputDetails?.reasoning !== undefined) {\n metrics.reasoning = usage.outputDetails.reasoning;\n }\n\n // 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_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"]}
|
package/dist/index.js
CHANGED
|
@@ -254,6 +254,14 @@ var LangfuseExporter = class extends TrackingExporter {
|
|
|
254
254
|
});
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Force flush any buffered data to Langfuse without shutting down.
|
|
259
|
+
*/
|
|
260
|
+
async _flush() {
|
|
261
|
+
if (this.#client) {
|
|
262
|
+
await this.#client.flushAsync();
|
|
263
|
+
}
|
|
264
|
+
}
|
|
257
265
|
async _postShutdown() {
|
|
258
266
|
if (this.#client) {
|
|
259
267
|
await this.#client.shutdownAsync();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/metrics.ts","../src/tracing.ts","../src/helpers.ts"],"names":[],"mappings":"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","file":"index.js","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 metrics.input = usage.inputTokens;\n\n if (usage.inputDetails?.cacheWrite !== undefined) {\n metrics.cache_write_input_tokens = usage.inputDetails.cacheWrite;\n metrics.input -= metrics.cache_write_input_tokens;\n }\n }\n\n if (usage.inputDetails?.cacheRead !== undefined) {\n metrics.cache_read_input_tokens = usage.inputDetails.cacheRead;\n }\n\n if (usage.outputTokens !== undefined) {\n metrics.output = usage.outputTokens;\n }\n\n if (usage.outputDetails?.reasoning !== undefined) {\n metrics.reasoning = usage.outputDetails.reasoning;\n }\n\n // 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_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 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/metrics.ts","../src/tracing.ts","../src/helpers.ts"],"names":[],"mappings":"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","file":"index.js","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 metrics.input = usage.inputTokens;\n\n if (usage.inputDetails?.cacheWrite !== undefined) {\n metrics.cache_write_input_tokens = usage.inputDetails.cacheWrite;\n metrics.input -= metrics.cache_write_input_tokens;\n }\n }\n\n if (usage.inputDetails?.cacheRead !== undefined) {\n metrics.cache_read_input_tokens = usage.inputDetails.cacheRead;\n }\n\n if (usage.outputTokens !== undefined) {\n metrics.output = usage.outputTokens;\n }\n\n if (usage.outputDetails?.reasoning !== undefined) {\n metrics.reasoning = usage.outputDetails.reasoning;\n }\n\n // 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_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"]}
|
package/dist/tracing.d.ts
CHANGED
|
@@ -86,6 +86,10 @@ export declare class LangfuseExporter extends TrackingExporter<LangfuseRoot, Lan
|
|
|
86
86
|
scorerName: string;
|
|
87
87
|
metadata?: Record<string, any>;
|
|
88
88
|
}): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Force flush any buffered data to Langfuse without shutting down.
|
|
91
|
+
*/
|
|
92
|
+
protected _flush(): Promise<void>;
|
|
89
93
|
_postShutdown(): Promise<void>;
|
|
90
94
|
}
|
|
91
95
|
export {};
|
package/dist/tracing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/langfuse",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.14",
|
|
4
4
|
"description": "Langfuse observability provider for Mastra - includes tracing and future observability features",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"langfuse": "^3.38.6",
|
|
28
|
-
"@mastra/observability": "1.0.0-beta.
|
|
28
|
+
"@mastra/observability": "1.0.0-beta.13"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "22.13.17",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"tsup": "^8.5.0",
|
|
36
36
|
"typescript": "^5.9.3",
|
|
37
37
|
"vitest": "4.0.16",
|
|
38
|
-
"@internal/types-builder": "0.0.28",
|
|
39
38
|
"@internal/lint": "0.0.53",
|
|
40
|
-
"@
|
|
39
|
+
"@internal/types-builder": "0.0.28",
|
|
40
|
+
"@mastra/core": "1.0.0-beta.24",
|
|
41
41
|
"@observability/test-utils": "0.0.1"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|