"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrewAIProvider = void 0;
const cache_1 = require("../../cache");
const logger_1 = __importDefault(require("../../logger"));
const shared_1 = require("../shared");
class CrewAIProvider {
    constructor(config, options = {}) {
        this.config = options.config || {};
        this.providerConfig = {
            ...config,
            pollIntervalMs: config?.pollIntervalMs || 2000, // 2 seconds default
            maxPollAttempts: config?.maxPollAttempts || 300, // 5 minutes max (300 * 2s = 600s)
        };
    }
    id() {
        return `crewai:${this.providerConfig.url}`;
    }
    async kickoff(prompt) {
        const url = `${this.providerConfig.url}/kickoff`;
        // Parse the prompt if it's a JSON string, otherwise treat it as plain text
        let inputs = {};
        try {
            const parsed = JSON.parse(prompt);
            // If the parsed object has an 'inputs' property, use it
            if (parsed && typeof parsed === 'object' && parsed.inputs) {
                inputs = parsed.inputs;
            }
            else if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
                // If it's an object without 'inputs', use the whole object as inputs
                inputs = parsed;
            }
            else {
                // If parsing fails or it's not an object, use prompt as a single input
                inputs = { prompt };
            }
        }
        catch {
            // Not JSON, use prompt as a single input
            inputs = { prompt };
        }
        const requestBody = {
            inputs,
            meta: {
                requestId: `req-${Date.now()}`,
                source: 'trusys',
            },
        };
        const options = {
            method: 'POST',
            headers: {
                Authorization: `Bearer ${this.providerConfig.apiKey}`,
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(requestBody),
        };
        logger_1.default.debug(`[CrewAI Provider]: Kicking off job at ${url}`);
        const response = await (0, cache_1.fetchWithCache)(url, options, shared_1.REQUEST_TIMEOUT_MS, 'json', false, 0);
        if (!response.data || !response.data.kickoff_id) {
            throw new Error(`Failed to kickoff CrewAI job: ${JSON.stringify(response.data)}`);
        }
        const kickoffId = response.data.kickoff_id;
        logger_1.default.debug(`[CrewAI Provider]: Kickoff successful, id: ${kickoffId}`);
        return kickoffId;
    }
    async pollStatus(kickoffId) {
        const url = `${this.providerConfig.url}/status/${kickoffId}`;
        const options = {
            method: 'GET',
            headers: {
                Authorization: `Bearer ${this.providerConfig.apiKey}`,
            },
        };
        const response = await (0, cache_1.fetchWithCache)(url, options, shared_1.REQUEST_TIMEOUT_MS, 'json', false, 0);
        if (!response.data) {
            throw new Error(`Failed to get CrewAI status: ${JSON.stringify(response)}`);
        }
        return response.data;
    }
    async waitForCompletion(kickoffId) {
        let attempts = 0;
        while (attempts < this.providerConfig.maxPollAttempts) {
            const status = await this.pollStatus(kickoffId);
            // Check both 'status' and 'state' fields (different API versions may use different fields)
            const currentState = status.state;
            logger_1.default.debug(`[CrewAI Provider]: Status check ${attempts + 1}/${this.providerConfig.maxPollAttempts}: status='${status.status}', state='${status.state}'`);
            // Check for completion - either status='completed' or state='SUCCESS'
            if (status.status === 'completed' || currentState === 'SUCCESS') {
                logger_1.default.debug(`[CrewAI Provider]: Job completed successfully`);
                return status;
            }
            // Check for error - either status='error' or state='ERROR'/'FAILED'
            if (status.status === 'error' || currentState === 'ERROR' || currentState === 'FAILED') {
                const errorMsg = status.error || 'Unknown error';
                logger_1.default.error(`[CrewAI Provider]: Job failed with error: ${errorMsg}`);
                throw new Error(`CrewAI job failed: ${errorMsg}`);
            }
            // Still running, wait and poll again
            await new Promise((resolve) => setTimeout(resolve, this.providerConfig.pollIntervalMs));
            attempts++;
        }
        throw new Error(`CrewAI job did not complete within ${this.providerConfig.maxPollAttempts * this.providerConfig.pollIntervalMs / 1000} seconds`);
    }
    async callApi(prompt, context) {
        try {
            // Step 1: Kickoff the job
            const kickoffId = await this.kickoff(prompt);
            // Step 2: Poll for completion
            const result = await this.waitForCompletion(kickoffId);
            // Step 3: Return the result
            // Extract output from various possible fields
            // The result can be directly in 'result' field as a string, or in 'result_json'
            const output = result?.result || result?.result_json || result?.output || '';
            const outputText = typeof output === 'string' ? output : (output?.output || JSON.stringify(output));
            return {
                output: outputText,
                metadata: {
                    kickoffId,
                    status: result?.status || result?.state,
                    state: result?.state,
                    executionTime: result?.execution_time,
                    tasks: result?.tasks,
                    progress: result?.progress,
                    lastExecutedTask: result?.last_executed_task,
                    lastStep: result?.last_step,
                },
            };
        }
        catch (err) {
            logger_1.default.error(`[CrewAI Provider]: Error calling API: ${String(err)}`);
            return {
                error: `CrewAI API error: ${String(err)}`,
            };
        }
    }
}
exports.CrewAIProvider = CrewAIProvider;
//# sourceMappingURL=crewai.js.map