UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio

173 lines 5.72 kB
/** * @file Langfuse Adapter * Integration with Langfuse for LLM observability */ import { logger } from "../../utils/logger.js"; import { observabilityHooks } from "./observabilityHooks.js"; /** * Langfuse adapter for evaluation observability */ export class LangfuseAdapter { _config; _unsubscribers = []; _traceIdMap = new Map(); constructor(config) { this._config = { scorePrefix: "eval", includeMetadata: true, tags: [], sendPipelineScores: true, sendScorerScores: true, ...config, }; } /** * Start listening to evaluation events */ start() { // Prevent duplicate subscriptions if (this._unsubscribers.length > 0) { return; } // Listen for scorer completions if (this._config.sendScorerScores) { const scorerUnsub = observabilityHooks.on("scorer:end", (event) => { this._sendScorerScore(event.result, event.traceContext?.traceId); }); this._unsubscribers.push(scorerUnsub); } // Listen for pipeline completions if (this._config.sendPipelineScores) { const pipelineUnsub = observabilityHooks.on("pipeline:end", (event) => { this._sendPipelineScores(event.result, event.traceContext?.traceId); }); this._unsubscribers.push(pipelineUnsub); } logger.debug("Langfuse adapter started"); } /** * Stop listening to events */ stop() { for (const unsub of this._unsubscribers) { unsub(); } this._unsubscribers = []; this._traceIdMap.clear(); logger.debug("Langfuse adapter stopped"); } /** * Send scorer score to Langfuse */ async _sendScorerScore(result, traceId) { try { const scoreName = `${this._config.scorePrefix}.${result.scorerId}`; const normalizedValue = result.normalizedScore; // Already 0-1 await this._config.client.score({ name: scoreName, value: normalizedValue, traceId, comment: result.reasoning, metadata: this._config.includeMetadata ? { passed: result.passed, threshold: result.threshold, computeTime: result.computeTime, confidence: result.confidence, ...(result.metadata ?? {}), } : undefined, }); logger.debug(`Sent score to Langfuse: ${scoreName}=${normalizedValue}`); } catch (error) { logger.error("Failed to send score to Langfuse", { scorerId: result.scorerId, error: error instanceof Error ? error.message : String(error), }); } } /** * Send pipeline scores to Langfuse */ async _sendPipelineScores(result, externalTraceId) { const traceId = externalTraceId ?? result.correlationId; const pipelineName = result.pipelineConfig.name ?? "unnamed"; try { // Send overall pipeline score await this._config.client.score({ name: `${this._config.scorePrefix}.pipeline.${pipelineName}.overall`, value: result.overallScore / 10, // Normalize to 0-1 traceId, comment: `Pipeline evaluation: ${result.passed ? "PASSED" : "FAILED"}`, metadata: this._config.includeMetadata ? { passed: result.passed, aggregationMethod: result.aggregationMethod, scorerCount: result.scores.length, totalComputeTime: result.totalComputeTime, errorCount: result.errors.length, } : undefined, }); logger.debug(`Sent pipeline score to Langfuse: ${pipelineName}=${result.overallScore / 10}`); } catch (error) { logger.error("Failed to send pipeline score to Langfuse", { pipelineName, error: error instanceof Error ? error.message : String(error), }); } } /** * Manually send a score to Langfuse */ async sendScore(name, value, options) { const scoreName = `${this._config.scorePrefix}.${name}`; await this._config.client.score({ name: scoreName, value, traceId: options?.traceId, comment: options?.comment, metadata: options?.metadata, }); } /** * Shutdown the adapter and flush any pending data */ async shutdown() { this.stop(); if (this._config.client.shutdown) { await this._config.client.shutdown(); } } } /** * Create a Langfuse adapter */ export function createLangfuseAdapter(config) { return new LangfuseAdapter(config); } /** * Create and start a Langfuse adapter */ export function startLangfuseAdapter(config) { const adapter = new LangfuseAdapter(config); adapter.start(); return adapter; } /** * Helper: Create a mock Langfuse client for testing */ export function createMockLangfuseClient() { const scores = []; return { scores, score: async (params) => { scores.push(params); return { id: `score-${scores.length}` }; }, shutdown: async () => { }, }; } //# sourceMappingURL=langfuseAdapter.js.map