"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;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.globalBase64ImageDetector = exports.Base64ImageProcessor = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
class Base64ImageProcessor {
    imageDetail = "auto";
    supportedFormats = ["png", "jpeg", "jpg", "gif", "webp"];
    constructor(toolsService) {
        this.registerTool(toolsService);
    }
    isBase64Image(text) {
        const dataUrlPattern = /^data:image\/([a-zA-Z]+);base64,(.+)$/;
        const match = text.match(dataUrlPattern);
        if (match) {
            const [, mimeType, data] = match;
            if (this.supportedFormats.includes(mimeType.toLowerCase())) {
                return { isImage: true, mimeType, data };
            }
        }
        const base64Pattern = /^[A-Za-z0-9+/]+=*$/;
        if (base64Pattern.test(text) && text.length > 100) {
            const header = text.substring(0, 50);
            try {
                const decoded = atob(header);
                if (decoded.startsWith("\x89PNG")) {
                    return { isImage: true, mimeType: "png", data: text };
                }
                else if (decoded.startsWith("\xFF\xD8\xFF")) {
                    return { isImage: true, mimeType: "jpeg", data: text };
                }
                else if (decoded.startsWith("GIF87a") ||
                    decoded.startsWith("GIF89a")) {
                    return { isImage: true, mimeType: "gif", data: text };
                }
                else if (decoded.startsWith("RIFF") && decoded.includes("WEBP")) {
                    return { isImage: true, mimeType: "webp", data: text };
                }
            }
            catch (e) {
            }
        }
        return { isImage: false };
    }
    convertBase64ToImageContent(text) {
        const detection = this.isBase64Image(text);
        if (!detection.isImage) {
            return null;
        }
        const dataUrl = detection.data.startsWith("data:")
            ? detection.data
            : `data:image/${detection.mimeType};base64,${detection.data}`;
        return {
            type: "image_url",
            image_url: {
                url: dataUrl,
                detail: this.imageDetail,
            },
        };
    }
    processMessageContent(message) {
        if (typeof message.content === "string") {
            const imageContent = this.convertBase64ToImageContent(message.content);
            if (imageContent) {
                message.content = [imageContent];
            }
        }
        else if (Array.isArray(message.content)) {
            const newContent = [];
            for (const item of message.content) {
                if (item.type === "text" && item.text) {
                    const imageContent = this.convertBase64ToImageContent(item.text);
                    if (imageContent) {
                        newContent.push(imageContent);
                    }
                    else {
                        newContent.push(item);
                    }
                }
                else {
                    newContent.push(item);
                }
            }
            message.content = newContent;
        }
    }
    processToolCallArguments(message) {
        if (message.tool_calls) {
            for (const toolCall of message.tool_calls) {
                if (toolCall.function.arguments) {
                    try {
                        const args = JSON.parse(toolCall.function.arguments);
                        let modified = false;
                        const processValue = (obj) => {
                            if (typeof obj === "string") {
                                const detection = this.isBase64Image(obj);
                                if (detection.isImage) {
                                    modified = true;
                                    const dataUrl = detection.data.startsWith("data:")
                                        ? detection.data
                                        : `data:image/${detection.mimeType};base64,${detection.data}`;
                                    return `[CONVERTED TO IMAGE: ${dataUrl.substring(0, 50)}...]`;
                                }
                                return obj;
                            }
                            else if (Array.isArray(obj)) {
                                return obj.map(processValue);
                            }
                            else if (obj && typeof obj === "object") {
                                const result = {};
                                for (const [key, value] of Object.entries(obj)) {
                                    result[key] = processValue(value);
                                }
                                return result;
                            }
                            return obj;
                        };
                        const processedArgs = processValue(args);
                        if (modified) {
                            toolCall.function.arguments = JSON.stringify(processedArgs);
                        }
                    }
                    catch (e) {
                        const detection = this.isBase64Image(toolCall.function.arguments);
                        if (detection.isImage) {
                            const dataUrl = detection.data.startsWith("data:")
                                ? detection.data
                                : `data:image/${detection.mimeType};base64,${detection.data}`;
                            toolCall.function.arguments = `[CONVERTED TO IMAGE: ${dataUrl.substring(0, 50)}...]`;
                        }
                    }
                }
            }
        }
    }
    processToolMessageContent(message) {
        if (typeof message.content === "string" && message.content.trim()) {
            try {
                const parsed = JSON.parse(message.content);
                if (parsed.type === "image_url" && parsed.image_url?.url) {
                    message.content = [parsed];
                }
            }
            catch (e) {
                if (typeof message.content === "string") {
                    const imageContent = this.convertBase64ToImageContent(message.content);
                    if (imageContent) {
                        message.content = [imageContent];
                    }
                }
            }
        }
    }
    createProcessor() {
        return (originalMessages, modifiedMessages) => {
            for (const message of modifiedMessages) {
                if (message.role === "user") {
                    this.processMessageContent(message);
                }
                if (message.role === "tool") {
                    this.processToolMessageContent(message);
                }
                this.processToolCallArguments(message);
            }
        };
    }
    setImageDetail(detail) {
        this.imageDetail = detail;
    }
    setSupportedFormats(formats) {
        this.supportedFormats = formats;
    }
    registerTool(toolsService) {
        if (toolsService) {
            const toolDefinition = {
                type: "function",
                function: {
                    name: "loadImageAsBase64",
                    description: "Load an image file from a file path and return it as a base64 data URL. This enables you to view and analyze images from the filesystem. Use this when the user provides a screenshot path or asks you to look at an image file.",
                    parameters: {
                        type: "object",
                        positional: true,
                        properties: {
                            filePath: {
                                type: "string",
                                description: "The absolute or relative path to the image file",
                            },
                            detail: {
                                type: "string",
                                description: "The level of detail for image analysis. Options: 'auto' (default), 'low' (faster, less detail), 'high' (slower, more detail)",
                            },
                        },
                        required: ["filePath"],
                    },
                },
            };
            toolsService.addTools([toolDefinition]);
            toolsService.addFunctions({
                loadImageAsBase64: async (filePath, detail) => {
                    return await this.loadImageAsBase64(filePath, detail);
                },
            });
        }
    }
    async loadImageAsBase64(filePath, detail = "auto") {
        try {
            if (!fs.existsSync(filePath)) {
                throw new Error(`File not found: ${filePath}`);
            }
            const stats = fs.statSync(filePath);
            if (!stats.isFile()) {
                throw new Error(`Path is not a file: ${filePath}`);
            }
            const ext = path.extname(filePath).toLowerCase().replace(".", "");
            const mimeTypeMap = {
                png: "image/png",
                jpg: "image/jpeg",
                jpeg: "image/jpeg",
                gif: "image/gif",
                webp: "image/webp",
                bmp: "image/bmp",
                svg: "image/svg+xml",
            };
            const mimeType = mimeTypeMap[ext];
            if (!mimeType) {
                throw new Error(`Unsupported image format: ${ext}. Supported formats: ${Object.keys(mimeTypeMap).join(", ")}`);
            }
            const simpleType = ext === "jpg" ? "jpeg" : ext;
            if (!this.supportedFormats.includes(simpleType)) {
                throw new Error(`Image format ${ext} is not in supported formats: ${this.supportedFormats.join(", ")}`);
            }
            const imageBuffer = fs.readFileSync(filePath);
            const base64Data = imageBuffer.toString("base64");
            const dataUrl = `data:${mimeType};base64,${base64Data}`;
            return JSON.stringify({
                type: "image_url",
                image_url: {
                    url: dataUrl,
                    detail: detail || this.imageDetail,
                },
            });
        }
        catch (error) {
            throw new Error(`Failed to load image: ${error.message}`);
        }
    }
}
exports.Base64ImageProcessor = Base64ImageProcessor;
exports.globalBase64ImageDetector = new Base64ImageProcessor();
//# sourceMappingURL=Base64ImageDetector.js.map