/**
 * @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