UNPKG

genkitx-langfuse

Version:

Genkit AI framework plugin for Langfuse observability and tracing.

1 lines 42.4 kB
{"version":3,"sources":["../src/index.ts","../src/telemetry-provider.ts","../src/exporter.ts","../src/metadata-extractor.ts"],"sourcesContent":["// Plugin interface based on genkit configuration structure\nimport { genkitPlugin, type GenkitPlugin } from 'genkit/plugin';\nimport { enableTelemetry } from 'genkit/tracing';\nimport { LangfuseTelemetryProvider } from './telemetry-provider.js';\nimport type { LangfuseConfig } from './types.js';\n\n/**\n * Langfuse plugin for Genkit that enables observability and tracing.\n * \n * @param config Langfuse configuration options\n * @returns Genkit plugin configuration\n * \n * @example\n * ```typescript\n * import { genkit } from 'genkit';\n * import { langfuse } from 'genkit-langfuse';\n * \n * const ai = genkit({\n * plugins: [\n * langfuse({\n * secretKey: process.env.LANGFUSE_SECRET_KEY!,\n * publicKey: process.env.LANGFUSE_PUBLIC_KEY!,\n * baseUrl: process.env.LANGFUSE_BASE_URL, // optional\n * debug: true, // optional\n * })\n * ],\n * });\n * ```\n */\nexport function langfuse(config: LangfuseConfig): GenkitPlugin {\n return genkitPlugin('langfuse', async () => {\n if (config.debug) {\n console.log('🔧 [DEBUG] Initializing Langfuse plugin');\n }\n \n const telemetryProvider = new LangfuseTelemetryProvider(config);\n \n // Enable telemetry through genkit's enableTelemetry function\n await enableTelemetry(telemetryProvider.getConfig());\n \n if (config.debug) {\n console.log('✅ [DEBUG] Langfuse plugin initialization complete');\n }\n });\n}\n\n/**\n * @deprecated Use `langfuse()` plugin instead\n * Legacy function for backward compatibility.\n */\nexport async function enableLangfuseTelemetry(config: LangfuseConfig) {\n console.warn('enableLangfuseTelemetry is deprecated. Use langfuse() plugin instead.');\n const telemetryProvider = new LangfuseTelemetryProvider(config);\n const { enableTelemetry } = await import('genkit/tracing');\n return enableTelemetry(telemetryProvider.getConfig());\n}\n\n/**\n * Creates a Langfuse telemetry provider without enabling it globally.\n * Useful for custom telemetry setups.\n * \n * @param config Langfuse configuration options\n * @returns LangfuseTelemetryProvider instance\n */\nexport function createLangfuseTelemetryProvider(config: LangfuseConfig): LangfuseTelemetryProvider {\n return new LangfuseTelemetryProvider(config);\n}\n\n// Re-export types and utilities\nexport type { LangfuseConfig, SpanData } from './types.js';\nexport { LangfuseExporter } from './exporter.js';\nexport { SpanMetadataExtractor } from './metadata-extractor.js';\nexport { LangfuseTelemetryProvider } from './telemetry-provider.js';","import { Resource } from '@opentelemetry/resources';\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport type { TelemetryConfig } from 'genkit';\nimport { LangfuseExporter } from './exporter.js';\nimport type { LangfuseConfig } from './types.js';\n\n/**\n * Telemetry provider that configures OpenTelemetry to export to Langfuse.\n */\nexport class LangfuseTelemetryProvider {\n private config: LangfuseConfig;\n private exporter?: LangfuseExporter;\n\n constructor(config: LangfuseConfig) {\n this.config = config;\n this.validateConfig();\n }\n\n /**\n * Get the telemetry configuration for Genkit.\n */\n getConfig(): TelemetryConfig {\n const config = {\n resource: this.createResource(),\n spanProcessors: [this.createSpanProcessor()], // Back to plural like official plugin\n instrumentations: [],\n };\n \n if (this.config.debug) {\n console.log('🔧 [DEBUG] Telemetry config created:', {\n resourceAttributes: config.resource.attributes,\n spanProcessorCount: config.spanProcessors.length,\n instrumentationCount: config.instrumentations.length,\n });\n }\n \n return config;\n }\n\n /**\n * Shutdown the telemetry provider.\n */\n async shutdown(): Promise<void> {\n if (this.exporter) {\n await this.exporter.shutdown();\n }\n }\n\n /**\n * Force flush all pending telemetry data.\n */\n async flush(): Promise<void> {\n if (this.exporter) {\n await this.exporter.forceFlush();\n }\n }\n\n /**\n * Create OpenTelemetry resource with Langfuse-specific attributes.\n */\n private createResource(): Resource {\n return new Resource({\n 'service.name': 'genkit-langfuse',\n 'service.version': '1.0.0',\n 'genkit.plugin': '@genkit-ai/langfuse',\n 'langfuse.version': this.getLangfuseVersion(),\n });\n }\n\n /**\n * Create the span processor with Langfuse exporter.\n */\n private createSpanProcessor(): BatchSpanProcessor {\n this.exporter = new LangfuseExporter(this.config);\n \n // Configure for development vs production following Genkit patterns\n const isDevelopment = this.config.forceDevExport || process.env.NODE_ENV === 'development';\n \n const processor = new BatchSpanProcessor(this.exporter, {\n maxExportBatchSize: isDevelopment ? (this.config.flushAt || 1) : (this.config.flushAt || 20),\n scheduledDelayMillis: isDevelopment ? (this.config.flushInterval || 1000) : (this.config.flushInterval || 10000),\n exportTimeoutMillis: this.config.exportTimeoutMillis || 30000,\n maxQueueSize: this.config.maxQueueSize || 1000,\n });\n \n if (this.config.debug) {\n console.log('🔧 [DEBUG] BatchSpanProcessor created with config:', {\n isDevelopment,\n maxExportBatchSize: processor['_maxExportBatchSize'] || (isDevelopment ? 1 : 20),\n scheduledDelayMillis: processor['_scheduledDelayMillis'] || (isDevelopment ? 1000 : 10000),\n exportTimeoutMillis: this.config.exportTimeoutMillis || 30000,\n maxQueueSize: this.config.maxQueueSize || 1000,\n });\n \n // Wrap processor methods to debug span activity\n const originalOnStart = processor.onStart;\n const originalOnEnd = processor.onEnd;\n \n processor.onStart = function(span, parentContext) {\n console.log(`🔥 [DEBUG] Span started: ${span.name} (${span.spanContext().spanId})`);\n return originalOnStart.call(this, span, parentContext);\n };\n \n processor.onEnd = function(span) {\n console.log(`🏁 [DEBUG] Span ended: ${span.name} (${span.spanContext().spanId})`);\n return originalOnEnd.call(this, span);\n };\n }\n \n return processor;\n }\n\n /**\n * Validate the configuration.\n */\n private validateConfig(): void {\n if (!this.config.secretKey) {\n throw new Error('Langfuse secret key is required');\n }\n if (!this.config.publicKey) {\n throw new Error('Langfuse public key is required');\n }\n\n // Set defaults following Genkit patterns\n const isDevelopment = this.config.forceDevExport || process.env.NODE_ENV === 'development';\n \n this.config.baseUrl = this.config.baseUrl || 'https://cloud.langfuse.com';\n this.config.debug = this.config.debug || false;\n \n // Use development-friendly defaults when appropriate\n if (isDevelopment) {\n this.config.flushAt = this.config.flushAt ?? 1; // Immediate export in dev\n this.config.flushInterval = this.config.flushInterval ?? 1000; // 1 second in dev\n } else {\n this.config.flushAt = this.config.flushAt ?? 20; // Batch in production\n this.config.flushInterval = this.config.flushInterval ?? 10000; // 10 seconds in production\n }\n \n this.config.exportTimeoutMillis = this.config.exportTimeoutMillis ?? 30000;\n this.config.maxQueueSize = this.config.maxQueueSize ?? 1000;\n }\n\n /**\n * Get the Langfuse SDK version.\n */\n private getLangfuseVersion(): string {\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const packageJson = require('langfuse/package.json');\n return packageJson.version;\n } catch (error) {\n return 'unknown';\n }\n }\n}","import { hrTimeToMilliseconds } from '@opentelemetry/core';\nimport type {\n ReadableSpan,\n SpanExporter,\n} from '@opentelemetry/sdk-trace-base';\nimport { ExportResult, ExportResultCode } from '@opentelemetry/core';\nimport { Langfuse } from 'langfuse';\nimport type { LangfuseConfig } from './types.js';\nimport { SpanMetadataExtractor } from './metadata-extractor.js';\n\n/**\n * Langfuse OpenTelemetry span exporter that sends Genkit traces to Langfuse.\n */\nexport class LangfuseExporter implements SpanExporter {\n private langfuse: Langfuse;\n private config: LangfuseConfig;\n private exportCount: number = 0;\n\n constructor(config: LangfuseConfig) {\n this.config = config;\n \n if (config.debug) {\n console.log('🔧 [DEBUG] Initializing Langfuse exporter with config:', {\n baseUrl: config.baseUrl,\n publicKey: config.publicKey ? `${config.publicKey.substring(0, 8)}...` : 'undefined',\n secretKey: config.secretKey ? `${config.secretKey.substring(0, 8)}...` : 'undefined',\n flushAt: config.flushAt || 20,\n flushInterval: config.flushInterval || 10000,\n });\n }\n \n this.langfuse = new Langfuse({\n secretKey: config.secretKey,\n publicKey: config.publicKey,\n baseUrl: config.baseUrl,\n flushAt: config.flushAt || 20,\n flushInterval: config.flushInterval || 10000,\n });\n\n // Add comprehensive error handling and debug logging\n this.langfuse.on('error', (error) => {\n console.error('🚨 [ERROR] Langfuse SDK error:', error);\n if (config.debug) {\n console.error('🔍 [DEBUG] Error details:', {\n message: error.message,\n stack: error.stack,\n name: error.name,\n });\n }\n });\n \n // Add HTTP success debugging if available\n if (config.debug && this.langfuse.on) {\n // Try to listen for success events if the SDK supports them\n try {\n this.langfuse.on('trace', () => {\n console.log('✅ [DEBUG] Langfuse trace event sent successfully');\n });\n } catch (e) {\n // SDK might not support this event\n }\n }\n\n // Add debug logging for successful operations\n if (config.debug) {\n this.langfuse.on('flush', () => {\n console.log('✅ [DEBUG] Langfuse flush completed');\n });\n }\n\n if (config.debug) {\n console.log('✅ [DEBUG] Langfuse exporter initialized successfully');\n this.testConnection();\n }\n }\n\n /**\n * Export spans to Langfuse.\n */\n export(\n spans: ReadableSpan[],\n resultCallback: (result: ExportResult) => void\n ): void {\n this.exportCount++;\n if (this.config.debug) {\n console.log(`📤 [DEBUG] Export #${this.exportCount}: Exporting ${spans.length} spans to Langfuse`);\n spans.forEach((span, index) => {\n console.log(` Span ${index + 1}: ${span.name} (${span.spanContext().spanId})`);\n });\n }\n \n try {\n let successCount = 0;\n let errorCount = 0;\n \n for (const span of spans) {\n try {\n this.processSpan(span);\n successCount++;\n } catch (spanError) {\n errorCount++;\n console.error(`🚨 [ERROR] Failed to process span ${span.name}:`, spanError);\n if (this.config.debug) {\n console.error('🔍 [DEBUG] Span details:', {\n spanId: span.spanContext().spanId,\n traceId: span.spanContext().traceId,\n name: span.name,\n attributes: span.attributes,\n });\n }\n }\n }\n \n if (this.config.debug) {\n console.log(`📊 [DEBUG] Export summary: ${successCount} successful, ${errorCount} failed`);\n }\n \n // Trigger immediate flush for debug visibility with success logging\n if (this.config.debug && successCount > 0) {\n this.langfuse.flushAsync()\n .then(() => {\n console.log('✅ [DEBUG] Post-export flush completed successfully');\n })\n .catch(error => {\n console.error('🚨 [ERROR] Failed to flush after export:', error);\n });\n }\n \n resultCallback({ code: ExportResultCode.SUCCESS });\n } catch (error) {\n console.error('🚨 [ERROR] Langfuse export error:', error);\n if (this.config.debug) {\n console.error('🔍 [DEBUG] Export error details:', {\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n resultCallback({ \n code: ExportResultCode.FAILED, \n error: error instanceof Error ? error : new Error(String(error))\n });\n }\n }\n\n /**\n * Test connection to Langfuse (for debugging).\n */\n private async testConnection(): Promise<void> {\n if (!this.config.debug) return;\n \n try {\n console.log('🔍 [DEBUG] Testing Langfuse connection...');\n console.log('🔍 [DEBUG] Langfuse API URL:', this.config.baseUrl);\n \n // Create a simple test trace to verify connectivity\n const testTrace = {\n id: 'test-connection-' + Date.now(),\n name: 'Connection Test',\n timestamp: new Date(),\n metadata: { test: true },\n };\n \n this.langfuse.trace(testTrace);\n \n // Attempt immediate flush\n console.log('🔍 [DEBUG] Flushing connection test trace...');\n await this.langfuse.flushAsync();\n console.log('✅ [DEBUG] Langfuse connection test completed');\n } catch (error) {\n console.error('🚨 [ERROR] Langfuse connection test failed:', error);\n }\n }\n\n /**\n * Shutdown the exporter.\n */\n async shutdown(): Promise<void> {\n if (this.config.debug) {\n console.log('🔄 [DEBUG] Shutting down Langfuse exporter...');\n }\n \n try {\n await this.langfuse.shutdownAsync();\n if (this.config.debug) {\n console.log('✅ [DEBUG] Langfuse exporter shutdown completed');\n }\n } catch (error) {\n console.error('🚨 [ERROR] Error during Langfuse exporter shutdown:', error);\n throw error;\n }\n }\n\n /**\n * Force flush all pending spans.\n */\n async forceFlush(): Promise<void> {\n if (this.config.debug) {\n console.log('🔄 [DEBUG] Force flushing Langfuse data...');\n }\n \n try {\n await this.langfuse.flushAsync();\n if (this.config.debug) {\n console.log('✅ [DEBUG] Langfuse force flush completed');\n }\n } catch (error) {\n console.error('🚨 [ERROR] Error during Langfuse force flush:', error);\n throw error;\n }\n }\n\n /**\n * Process a single span and send to Langfuse.\n */\n private processSpan(span: ReadableSpan): void {\n const metadata = SpanMetadataExtractor.extractMetadata(span);\n const spanType = this.determineSpanType(span, metadata);\n\n if (this.config.debug) {\n console.log(`🔍 [DEBUG] Processing span: ${span.name}`);\n console.log(` Type: ${spanType}`);\n console.log(` Path: ${metadata.path || 'unknown'}`);\n console.log(` SpanID: ${span.spanContext().spanId}`);\n console.log(` TraceID: ${span.spanContext().traceId}`);\n console.log(` ParentID: ${span.parentSpanId || 'none'}`);\n console.log(` Duration: ${hrTimeToMilliseconds(span.endTime) - hrTimeToMilliseconds(span.startTime)}ms`);\n }\n\n try {\n switch (spanType) {\n case 'generation':\n this.createGeneration(span, metadata);\n break;\n case 'trace':\n this.createTrace(span, metadata);\n break;\n case 'span':\n this.createSpan(span, metadata);\n break;\n default:\n if (this.config.debug) {\n console.log(`⚠️ [WARNING] Skipping span with unknown type: ${span.name} (type: ${spanType})`);\n }\n return;\n }\n \n if (this.config.debug) {\n console.log(`✅ [DEBUG] Successfully created Langfuse ${spanType}: ${span.name}`);\n }\n } catch (error) {\n console.error(`🚨 [ERROR] Failed to create Langfuse ${spanType} for span ${span.name}:`, error);\n throw error; // Re-throw to be caught by export method\n }\n }\n\n /**\n * Determine the Langfuse span type based on Genkit span data.\n */\n private determineSpanType(span: ReadableSpan, metadata: any): string {\n const spanType = metadata.spanType;\n const path = metadata.path;\n const name = span.name;\n\n // Model/LLM calls are generations\n if (spanType === 'model' || \n path?.includes('/model/') ||\n name.includes('generate') ||\n name.includes('model')) {\n return 'generation';\n }\n\n // Root spans, flow spans, or spans with no parent are traces\n if (metadata.isRoot || \n spanType === 'flow' ||\n path?.includes('/flow/') ||\n !span.parentSpanId ||\n span.parentSpanId === '0000000000000000') {\n return 'trace';\n }\n\n // Tool calls and other intermediate operations\n if (spanType === 'tool' || \n path?.includes('/tool/') ||\n name.includes('tool') ||\n name.includes('Tool')) {\n return 'span';\n }\n\n // Everything else is a span\n return 'span';\n }\n\n /**\n * Create a Langfuse generation (for LLM calls) using latest SDK v3 patterns.\n */\n private createGeneration(span: ReadableSpan, metadata: any): void {\n const input = this.parseJSON(metadata.input);\n const output = this.parseJSON(metadata.output);\n const modelName = metadata.name || this.extractModelFromPath(metadata.path);\n \n const generationData: any = {\n id: span.spanContext().spanId,\n traceId: span.spanContext().traceId,\n name: span.name,\n model: modelName,\n input: input, // SDK v3 uses input instead of prompt\n output: output, // SDK v3 uses output instead of completion\n startTime: new Date(hrTimeToMilliseconds(span.startTime)),\n endTime: new Date(hrTimeToMilliseconds(span.endTime)),\n metadata: {\n genkit: true,\n spanType: metadata.spanType,\n path: metadata.path,\n state: metadata.state,\n provider: this.extractProviderFromPath(metadata.path),\n genkitVersion: '1.x',\n parentSpanId: span.parentSpanId,\n },\n };\n\n // Add parent span ID if available\n if (span.parentSpanId && span.parentSpanId !== '0000000000000000') {\n generationData.parentObservationId = span.parentSpanId;\n }\n\n // Add token usage in the SDK v3 format\n if (output && output.usage) {\n generationData.usage = {\n input: output.usage.inputTokens,\n output: output.usage.outputTokens,\n total: output.usage.totalTokens,\n };\n\n // Add cost calculation if custom function provided\n if (this.config.calculateCost) {\n try {\n generationData.totalCost = this.config.calculateCost(\n modelName,\n {\n inputTokens: output.usage.inputTokens || 0,\n outputTokens: output.usage.outputTokens || 0,\n totalTokens: output.usage.totalTokens || 0,\n }\n );\n } catch (error) {\n console.warn('⚠️ [WARNING] Failed to calculate cost:', error);\n }\n }\n }\n\n // Add session info if available\n if (metadata.sessionId) {\n generationData.sessionId = metadata.sessionId;\n }\n\n // Add user info if available\n if (metadata.userId) {\n generationData.userId = metadata.userId;\n }\n\n // Add version info if available\n if (metadata.version) {\n generationData.version = metadata.version;\n }\n\n if (this.config.debug) {\n console.log('🤖 [DEBUG] Creating Langfuse generation with data:', {\n id: generationData.id,\n traceId: generationData.traceId,\n name: generationData.name,\n model: generationData.model,\n inputSize: JSON.stringify(input || {}).length,\n outputSize: JSON.stringify(output || {}).length,\n usage: generationData.usage,\n hasParent: !!generationData.parentObservationId,\n });\n }\n\n try {\n this.langfuse.generation(generationData);\n if (this.config.debug) {\n console.log(`✅ [DEBUG] Langfuse generation created: ${span.name} (${modelName})`);\n }\n } catch (error) {\n console.error('🚨 [ERROR] Failed to create Langfuse generation:', error);\n throw error;\n }\n }\n\n /**\n * Create a Langfuse trace (for root spans/flows).\n */\n private createTrace(span: ReadableSpan, metadata: any): void {\n const input = this.parseJSON(metadata.input);\n const output = this.parseJSON(metadata.output);\n\n const trace = {\n id: span.spanContext().traceId,\n name: span.name,\n input: input,\n output: output,\n timestamp: new Date(hrTimeToMilliseconds(span.startTime)),\n metadata: {\n spanType: metadata.spanType,\n path: metadata.path,\n state: metadata.state,\n duration: hrTimeToMilliseconds(span.endTime) - hrTimeToMilliseconds(span.startTime),\n genkit: true,\n },\n };\n\n // Add session info if available\n const sessionId = metadata.sessionId;\n if (sessionId) {\n (trace as any).sessionId = sessionId;\n }\n\n // Add user info if available\n const userId = metadata.userId;\n if (userId) {\n (trace as any).userId = userId;\n }\n\n if (this.config.debug) {\n console.log('🏁 [DEBUG] Creating Langfuse trace with data:', {\n id: trace.id,\n name: trace.name,\n inputSize: JSON.stringify(input || {}).length,\n outputSize: JSON.stringify(output || {}).length,\n duration: trace.metadata.duration,\n hasSession: !!sessionId,\n hasUser: !!userId,\n });\n }\n\n try {\n this.langfuse.trace(trace);\n if (this.config.debug) {\n console.log(`✅ [DEBUG] Langfuse trace created: ${span.name}`);\n }\n } catch (error) {\n console.error('🚨 [ERROR] Failed to create Langfuse trace:', error);\n throw error;\n }\n }\n\n /**\n * Create a Langfuse span (for intermediate operations).\n */\n private createSpan(span: ReadableSpan, metadata: any): void {\n const input = this.parseJSON(metadata.input);\n const output = this.parseJSON(metadata.output);\n\n const langfuseSpan: any = {\n id: span.spanContext().spanId,\n traceId: span.spanContext().traceId,\n name: span.name,\n input: input,\n output: output,\n startTime: new Date(hrTimeToMilliseconds(span.startTime)),\n endTime: new Date(hrTimeToMilliseconds(span.endTime)),\n metadata: {\n genkit: true,\n spanType: metadata.spanType,\n path: metadata.path,\n state: metadata.state,\n parentSpanId: span.parentSpanId,\n },\n };\n\n // Add parent span ID if available\n if (span.parentSpanId && span.parentSpanId !== '0000000000000000') {\n langfuseSpan.parentObservationId = span.parentSpanId;\n }\n\n if (this.config.debug) {\n console.log('🔗 [DEBUG] Creating Langfuse span with data:', {\n id: langfuseSpan.id,\n traceId: langfuseSpan.traceId,\n name: langfuseSpan.name,\n inputSize: JSON.stringify(input || {}).length,\n outputSize: JSON.stringify(output || {}).length,\n hasParent: !!langfuseSpan.parentObservationId,\n });\n }\n\n try {\n this.langfuse.span(langfuseSpan);\n if (this.config.debug) {\n console.log(`✅ [DEBUG] Langfuse span created: ${span.name} (parent: ${span.parentSpanId || 'none'})`);\n }\n } catch (error) {\n console.error('🚨 [ERROR] Failed to create Langfuse span:', error);\n throw error;\n }\n }\n\n /**\n * Extract model name from Genkit path.\n */\n private extractModelFromPath(path?: string): string {\n if (!path) return 'unknown';\n const match = path.match(/\\/model\\/([^\\/]+)\\/([^\\/]+)/);\n return match ? match[2] : 'unknown';\n }\n\n /**\n * Extract provider name from Genkit path.\n */\n private extractProviderFromPath(path?: string): string {\n if (!path) return 'unknown';\n const match = path.match(/\\/model\\/([^\\/]+)\\//);\n return match ? match[1] : 'unknown';\n }\n\n /**\n * Safely parse JSON string.\n */\n private parseJSON(jsonString?: string): any {\n if (!jsonString || typeof jsonString !== 'string') {\n return jsonString;\n }\n try {\n return JSON.parse(jsonString);\n } catch (error) {\n return jsonString;\n }\n }\n}","import type { ReadableSpan } from '@opentelemetry/sdk-trace-base';\n\n/**\n * Extracts structured metadata from Genkit OpenTelemetry spans.\n */\nexport class SpanMetadataExtractor {\n /**\n * Extract all relevant metadata from a span.\n */\n static extractMetadata(span: ReadableSpan): ExtractedMetadata {\n const attributes = span.attributes;\n \n return {\n // Core Genkit attributes\n name: attributes['genkit:name'] as string,\n path: attributes['genkit:path'] as string,\n spanType: attributes['genkit:type'] as string,\n input: attributes['genkit:input'] as string,\n output: attributes['genkit:output'] as string,\n state: attributes['genkit:state'] as string,\n isRoot: attributes['genkit:isRoot'] === 'true' || attributes['genkit:isRoot'] === true,\n \n // Session tracking (available in chat flows)\n sessionId: attributes['genkit:sessionId'] as string,\n threadName: attributes['genkit:threadName'] as string,\n \n // User context (if available)\n userId: attributes['genkit:userId'] as string,\n \n // Additional metadata\n metadata: this.extractCustomMetadata(attributes),\n };\n }\n\n /**\n * Extract custom metadata from genkit:metadata:* attributes.\n */\n private static extractCustomMetadata(attributes: Record<string, any>): Record<string, any> {\n const metadata: Record<string, any> = {};\n \n for (const [key, value] of Object.entries(attributes)) {\n if (key.startsWith('genkit:metadata:')) {\n const metadataKey = key.replace('genkit:metadata:', '');\n metadata[metadataKey] = value;\n }\n }\n \n return metadata;\n }\n\n /**\n * Check if a span represents an LLM/model call.\n */\n static isModelSpan(span: ReadableSpan): boolean {\n const attributes = span.attributes;\n const spanType = attributes['genkit:type'] as string;\n const path = attributes['genkit:path'] as string;\n \n return spanType === 'model' || Boolean(path && path.includes('/model/'));\n }\n\n /**\n * Check if a span is a root trace span.\n */\n static isRootSpan(span: ReadableSpan): boolean {\n const attributes = span.attributes;\n return attributes['genkit:isRoot'] === 'true';\n }\n\n /**\n * Extract usage information from output.\n */\n static extractUsage(span: ReadableSpan): TokenUsage | null {\n const attributes = span.attributes;\n const output = attributes['genkit:output'] as string;\n \n if (!output) return null;\n \n try {\n const parsed = JSON.parse(output);\n if (parsed.usage) {\n return {\n inputTokens: parsed.usage.inputTokens || 0,\n outputTokens: parsed.usage.outputTokens || 0,\n totalTokens: parsed.usage.totalTokens || \n (parsed.usage.inputTokens || 0) + (parsed.usage.outputTokens || 0),\n };\n }\n } catch (error) {\n // Ignore parsing errors\n }\n \n return null;\n }\n\n /**\n * Extract model configuration from input.\n */\n static extractModelConfig(span: ReadableSpan): Record<string, any> | null {\n const attributes = span.attributes;\n const input = attributes['genkit:input'] as string;\n \n if (!input) return null;\n \n try {\n const parsed = JSON.parse(input);\n return parsed.config || null;\n } catch (error) {\n return null;\n }\n }\n}\n\nexport interface ExtractedMetadata {\n name?: string;\n path?: string;\n spanType?: string;\n input?: string;\n output?: string;\n state?: string;\n isRoot?: boolean;\n sessionId?: string;\n threadName?: string;\n userId?: string;\n metadata?: Record<string, any>;\n}\n\nexport interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n}"],"mappings":"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","names":["enableTelemetry"]}