"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleConversationRelevancy = void 0;
const child_process_1 = require("child_process");
const fs = __importStar(require("fs"));
const path_1 = __importDefault(require("path"));
const matchers_1 = require("../matchers");
const defaults_1 = require("../providers/defaults");
const invariant_1 = __importDefault(require("../util/invariant"));
/**
 * Find the correct Python executable for the current platform
 */
function findPythonExecutable() {
    const isWindows = process.platform === 'win32';
    // Helper to find Python in PATH on Windows
    const findPythonInPath = (command) => {
        if (!isWindows) {
            return null;
        }
        const pathEnv = process.env.PATH || '';
        const paths = pathEnv.split(path_1.default.delimiter);
        for (const dir of paths) {
            const pythonPath = path_1.default.join(dir, `${command}.exe`);
            if (fs.existsSync(pythonPath)) {
                return pythonPath;
            }
        }
        return null;
    };
    // Try to find the correct Python executable
    const possiblePythonPaths = isWindows
        ? ['./venv/Scripts/python.exe', './venv/Scripts/python']
        : ['./venv/bin/python3', './venv/bin/python'];
    let pythonExecutable = null;
    // First, try venv paths (relative to project root)
    const projectRoot = path_1.default.resolve(__dirname, '../../..');
    for (const pythonPath of possiblePythonPaths) {
        const fullPath = path_1.default.join(projectRoot, pythonPath);
        if (fs.existsSync(fullPath)) {
            pythonExecutable = fullPath;
            break;
        }
    }
    // If not found in venv, try to find in system PATH
    if (!pythonExecutable) {
        if (isWindows) {
            pythonExecutable =
                findPythonInPath('python') || findPythonInPath('python3') || findPythonInPath('py');
        }
        else {
            // For Unix-like systems, try common locations
            const unixPaths = [
                '/usr/local/bin/python3.10',
                '/usr/bin/python3.10',
                '/usr/local/bin/python3',
                '/usr/bin/python3',
                '/usr/bin/python',
            ];
            for (const unixPath of unixPaths) {
                if (fs.existsSync(unixPath)) {
                    pythonExecutable = unixPath;
                    break;
                }
            }
        }
    }
    // Fallback to system command (will require shell mode)
    if (!pythonExecutable) {
        pythonExecutable = isWindows ? 'python' : 'python3';
    }
    return pythonExecutable;
}
async function executeAndGradeConversationRelevancy(llmOutput, textProvider, providerType, context) {
    const pythonScriptPath = path_1.default.join(__dirname, 'python', 'conversation_relevancy_eval.py');
    const contextJson = JSON.stringify(context);
    const pythonExecutable = findPythonExecutable();
    const needsShell = !path_1.default.isAbsolute(pythonExecutable);
    const jsonPromise = new Promise((resolve, reject) => {
        const py = (0, child_process_1.spawn)(pythonExecutable, [pythonScriptPath, llmOutput, JSON.stringify(textProvider), providerType], {
            env: process.env,
            stdio: ['pipe', 'pipe', 'pipe'], // can be changed to inherit if desired
            shell: needsShell,
            windowsHide: true, // Hide console window on Windows
        });
        let stdoutData = '', stderrData = '';
        py.stdin.write(contextJson);
        py.stdin.end();
        py.stdout.on('data', (c) => (stdoutData += c.toString()));
        py.stderr.on('data', (c) => {
            stderrData += c.toString();
            // console.error("[conversation_relevancy.py stderr]:", c.toString());
        });
        py.on('close', (code) => {
            // console.error("[conversation_relevancy.py stderr(final)]:", stderrData.trim());
            if (code === 0) {
                resolve(stdoutData.trim());
            }
            else {
                reject(new Error(`Python exited with code ${code}. stdout="${stdoutData}", stderr="${stderrData}"`));
            }
        });
        py.on('error', (err) => reject(new Error(`Failed to start Python: ${err.message}`)));
    });
    try {
        return JSON.parse(await jsonPromise);
    }
    catch (e) {
        console.error('Invalid JSON from Python:', e);
        return { pass: false, score: 0, reason: 'evaluation failed' };
    }
}
const handleConversationRelevancy = async ({ assertion, outputString, test, context, workspaceId, }) => {
    (0, invariant_1.default)(typeof outputString === 'string', 'output must be string');
    const textProvider = await (0, matchers_1.getAndCheckProvider)('text', test.options?.provider, (await (0, defaults_1.getDefaultProviders)(undefined, workspaceId)).gradingProvider, 'conversation-relevancy');
    const providerType = textProvider.constructor.name;
    const contextForPython = context;
    const grading = await executeAndGradeConversationRelevancy(outputString, textProvider, providerType, contextForPython);
    return {
        assertion,
        pass: grading.pass,
        score: grading.score,
        reason: grading.reason,
    };
};
exports.handleConversationRelevancy = handleConversationRelevancy;
//# sourceMappingURL=conversationRelevancyAssertion.js.map